LCOV - code coverage report
Current view: top level - gfx/layers/client - TextureClientPool.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 132 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 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 "TextureClientPool.h"
       7             : #include "CompositableClient.h"
       8             : #include "mozilla/layers/CompositableForwarder.h"
       9             : #include "mozilla/layers/TextureForwarder.h"
      10             : #include "mozilla/layers/TiledContentClient.h"
      11             : 
      12             : #include "gfxPrefs.h"
      13             : 
      14             : #include "nsComponentManagerUtils.h"
      15             : 
      16             : #define TCP_LOG(...)
      17             : //#define TCP_LOG(...) printf_stderr(__VA_ARGS__);
      18             : 
      19             : namespace mozilla {
      20             : namespace layers {
      21             : 
      22             : // We want to shrink to our maximum size of N unused tiles
      23             : // after a timeout to allow for short-term budget requirements
      24             : static void
      25           0 : ShrinkCallback(nsITimer *aTimer, void *aClosure)
      26             : {
      27           0 :   static_cast<TextureClientPool*>(aClosure)->ShrinkToMaximumSize();
      28           0 : }
      29             : 
      30             : // After a certain amount of inactivity, let's clear the pool so that
      31             : // we don't hold onto tiles needlessly. In general, allocations are
      32             : // cheap enough that re-allocating isn't an issue unless we're allocating
      33             : // at an inopportune time (e.g. mid-animation).
      34             : static void
      35           0 : ClearCallback(nsITimer *aTimer, void *aClosure)
      36             : {
      37           0 :   static_cast<TextureClientPool*>(aClosure)->Clear();
      38           0 : }
      39             : 
      40           0 : TextureClientPool::TextureClientPool(LayersBackend aLayersBackend,
      41             :                                      int32_t aMaxTextureSize,
      42             :                                      gfx::SurfaceFormat aFormat,
      43             :                                      gfx::IntSize aSize,
      44             :                                      TextureFlags aFlags,
      45             :                                      uint32_t aShrinkTimeoutMsec,
      46             :                                      uint32_t aClearTimeoutMsec,
      47             :                                      uint32_t aInitialPoolSize,
      48             :                                      uint32_t aPoolUnusedSize,
      49           0 :                                      TextureForwarder* aAllocator)
      50             :   : mBackend(aLayersBackend)
      51             :   , mMaxTextureSize(aMaxTextureSize)
      52             :   , mFormat(aFormat)
      53             :   , mSize(aSize)
      54             :   , mFlags(aFlags)
      55             :   , mShrinkTimeoutMsec(aShrinkTimeoutMsec)
      56             :   , mClearTimeoutMsec(aClearTimeoutMsec)
      57             :   , mInitialPoolSize(aInitialPoolSize)
      58             :   , mPoolUnusedSize(aPoolUnusedSize)
      59             :   , mOutstandingClients(0)
      60             :   , mSurfaceAllocator(aAllocator)
      61           0 :   , mDestroyed(false)
      62             : {
      63             :   TCP_LOG("TexturePool %p created with maximum unused texture clients %u\n",
      64             :       this, mInitialPoolSize);
      65           0 :   mShrinkTimer = do_CreateInstance("@mozilla.org/timer;1");
      66           0 :   mClearTimer = do_CreateInstance("@mozilla.org/timer;1");
      67           0 :   if (aFormat == gfx::SurfaceFormat::UNKNOWN) {
      68           0 :     gfxWarning() << "Creating texture pool for SurfaceFormat::UNKNOWN format";
      69             :   }
      70           0 : }
      71             : 
      72           0 : TextureClientPool::~TextureClientPool()
      73             : {
      74           0 :   mShrinkTimer->Cancel();
      75           0 :   mClearTimer->Cancel();
      76           0 : }
      77             : 
      78             : #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
      79           0 : static bool TestClientPool(const char* what,
      80             :                            TextureClient* aClient,
      81             :                            TextureClientPool* aPool)
      82             : {
      83           0 :   if (!aClient || !aPool) {
      84           0 :     return false;
      85             :   }
      86             : 
      87           0 :   TextureClientPool* actual = aClient->mPoolTracker;
      88           0 :   bool ok = (actual == aPool);
      89           0 :   if (ok) {
      90           0 :     ok = (aClient->GetFormat() == aPool->GetFormat());
      91             :   }
      92             : 
      93           0 :   if (!ok) {
      94           0 :     if (actual) {
      95           0 :       gfxCriticalError() << "Pool error(" << what << "): "
      96           0 :                    << aPool << "-" << aPool->GetFormat() << ", "
      97           0 :                    << actual << "-" << actual->GetFormat() << ", "
      98           0 :                    << aClient->GetFormat();
      99           0 :       MOZ_CRASH("GFX: Crashing with actual");
     100             :     } else {
     101           0 :       gfxCriticalError() << "Pool error(" << what << "): "
     102           0 :                    << aPool << "-" << aPool->GetFormat() << ", nullptr, "
     103           0 :                    << aClient->GetFormat();
     104           0 :       MOZ_CRASH("GFX: Crashing without actual");
     105             :     }
     106             :   }
     107           0 :   return ok;
     108             : }
     109             : #endif
     110             : 
     111             : already_AddRefed<TextureClient>
     112           0 : TextureClientPool::GetTextureClient()
     113             : {
     114             :   // Try to fetch a client from the pool
     115           0 :   RefPtr<TextureClient> textureClient;
     116             : 
     117             :   // We initially allocate mInitialPoolSize for our pool. If we run
     118             :   // out of TextureClients, we allocate additional TextureClients to try and keep around
     119             :   // mPoolUnusedSize
     120           0 :   if (!mTextureClients.size()) {
     121           0 :     AllocateTextureClient();
     122             :   }
     123             : 
     124           0 :   if (!mTextureClients.size()) {
     125             :     // All our allocations failed, return nullptr
     126           0 :     return nullptr;
     127             :   }
     128             : 
     129           0 :   mOutstandingClients++;
     130           0 :   textureClient = mTextureClients.top();
     131           0 :   mTextureClients.pop();
     132             : #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
     133           0 :   if (textureClient) {
     134           0 :     textureClient->mPoolTracker = this;
     135             :   }
     136           0 :   DebugOnly<bool> ok = TestClientPool("fetch", textureClient, this);
     137           0 :   MOZ_ASSERT(ok);
     138             : #endif
     139             :   TCP_LOG("TexturePool %p giving %p from pool; size %u outstanding %u\n",
     140             :       this, textureClient.get(), mTextureClients.size(), mOutstandingClients);
     141             : 
     142           0 :   return textureClient.forget();
     143             : }
     144             : 
     145             : void
     146           0 : TextureClientPool::AllocateTextureClient()
     147             : {
     148             :   TCP_LOG("TexturePool %p allocating TextureClient, outstanding %u\n",
     149             :       this, mOutstandingClients);
     150             : 
     151           0 :   RefPtr<TextureClient> newClient;
     152           0 :   if (gfxPrefs::ForceShmemTiles()) {
     153             :     // gfx::BackendType::NONE means use the content backend
     154             :     newClient =
     155           0 :       TextureClient::CreateForRawBufferAccess(mSurfaceAllocator,
     156             :                                               mFormat, mSize,
     157             :                                               gfx::BackendType::NONE,
     158             :                                               mBackend,
     159           0 :                                               mFlags, ALLOC_DEFAULT);
     160             :   } else {
     161             :     newClient =
     162           0 :       TextureClient::CreateForDrawing(mSurfaceAllocator,
     163             :                                       mFormat, mSize,
     164             :                                       mBackend,
     165             :                                       mMaxTextureSize,
     166             :                                       BackendSelector::Content,
     167           0 :                                       mFlags);
     168             :   }
     169             : 
     170           0 :   if (newClient) {
     171           0 :     mTextureClients.push(newClient);
     172             :   }
     173           0 : }
     174             : 
     175             : void
     176           0 : TextureClientPool::ResetTimers()
     177             : {
     178             :   // Shrink down if we're beyond our maximum size
     179           0 :   if (mShrinkTimeoutMsec &&
     180           0 :       mTextureClients.size() + mTextureClientsDeferred.size() > mPoolUnusedSize) {
     181             :     TCP_LOG("TexturePool %p scheduling a shrink-to-max-size\n", this);
     182           0 :     mShrinkTimer->InitWithNamedFuncCallback(
     183             :       ShrinkCallback,
     184             :       this,
     185             :       mShrinkTimeoutMsec,
     186             :       nsITimer::TYPE_ONE_SHOT,
     187           0 :       "layers::TextureClientPool::ResetTimers");
     188             :   }
     189             : 
     190             :   // Clear pool after a period of inactivity to reduce memory consumption
     191           0 :   if (mClearTimeoutMsec) {
     192             :     TCP_LOG("TexturePool %p scheduling a clear\n", this);
     193           0 :     mClearTimer->InitWithNamedFuncCallback(
     194             :       ClearCallback,
     195             :       this,
     196             :       mClearTimeoutMsec,
     197             :       nsITimer::TYPE_ONE_SHOT,
     198           0 :       "layers::TextureClientPool::ResetTimers");
     199             :   }
     200           0 : }
     201             : 
     202             : void
     203           0 : TextureClientPool::ReturnTextureClient(TextureClient *aClient)
     204             : {
     205           0 :   if (!aClient || mDestroyed) {
     206           0 :     return;
     207             :   }
     208             : #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
     209           0 :   DebugOnly<bool> ok = TestClientPool("return", aClient, this);
     210           0 :   MOZ_ASSERT(ok);
     211             : #endif
     212             :   // Add the client to the pool:
     213           0 :   MOZ_ASSERT(mOutstandingClients > mTextureClientsDeferred.size());
     214           0 :   mOutstandingClients--;
     215           0 :   mTextureClients.push(aClient);
     216             :   TCP_LOG("TexturePool %p had client %p returned; size %u outstanding %u\n",
     217             :       this, aClient, mTextureClients.size(), mOutstandingClients);
     218             : 
     219           0 :   ResetTimers();
     220             : }
     221             : 
     222             : void
     223           0 : TextureClientPool::ReturnTextureClientDeferred(TextureClient* aClient)
     224             : {
     225           0 :   if (!aClient || mDestroyed) {
     226           0 :     return;
     227             :   }
     228           0 :   MOZ_ASSERT(aClient->GetReadLock());
     229             : #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
     230           0 :   DebugOnly<bool> ok = TestClientPool("defer", aClient, this);
     231           0 :   MOZ_ASSERT(ok);
     232             : #endif
     233           0 :   mTextureClientsDeferred.push_back(aClient);
     234             :   TCP_LOG("TexturePool %p had client %p defer-returned, size %u outstanding %u\n",
     235             :       this, aClient, mTextureClientsDeferred.size(), mOutstandingClients);
     236             : 
     237           0 :   ResetTimers();
     238             : }
     239             : 
     240             : void
     241           0 : TextureClientPool::ShrinkToMaximumSize()
     242             : {
     243             :   // We're over our desired maximum size, immediately shrink down to the
     244             :   // maximum.
     245             :   //
     246             :   // We cull from the deferred TextureClients first, as we can't reuse those
     247             :   // until they get returned.
     248           0 :   uint32_t totalUnusedTextureClients = mTextureClients.size() + mTextureClientsDeferred.size();
     249             : 
     250             :   // If we have > mInitialPoolSize outstanding, then we want to keep around
     251             :   // mPoolUnusedSize at a maximum. If we have fewer than mInitialPoolSize
     252             :   // outstanding, then keep around the entire initial pool size.
     253             :   uint32_t targetUnusedClients;
     254           0 :   if (mOutstandingClients > mInitialPoolSize) {
     255           0 :     targetUnusedClients = mPoolUnusedSize;
     256             :   } else {
     257           0 :     targetUnusedClients = mInitialPoolSize;
     258             :   }
     259             : 
     260             :   TCP_LOG("TexturePool %p shrinking to maximum unused size %u; current pool size %u; total outstanding %u\n",
     261             :       this, targetUnusedClients, totalUnusedTextureClients, mOutstandingClients);
     262             : 
     263           0 :   while (totalUnusedTextureClients > targetUnusedClients) {
     264           0 :     if (mTextureClientsDeferred.size()) {
     265           0 :       mOutstandingClients--;
     266             :       TCP_LOG("TexturePool %p dropped deferred client %p; %u remaining\n",
     267             :           this, mTextureClientsDeferred.front().get(),
     268             :           mTextureClientsDeferred.size() - 1);
     269           0 :       mTextureClientsDeferred.pop_front();
     270             :     } else {
     271             :       TCP_LOG("TexturePool %p dropped non-deferred client %p; %u remaining\n",
     272             :           this, mTextureClients.top().get(), mTextureClients.size() - 1);
     273           0 :       mTextureClients.pop();
     274             :     }
     275           0 :     totalUnusedTextureClients--;
     276             :   }
     277           0 : }
     278             : 
     279             : void
     280           0 : TextureClientPool::ReturnDeferredClients()
     281             : {
     282           0 :   if (mTextureClientsDeferred.empty()) {
     283           0 :     return;
     284             :   }
     285             : 
     286             :   TCP_LOG("TexturePool %p returning %u deferred clients to pool\n",
     287             :       this, mTextureClientsDeferred.size());
     288             : 
     289           0 :   ReturnUnlockedClients();
     290           0 :   ShrinkToMaximumSize();
     291             : }
     292             : 
     293             : void
     294           0 : TextureClientPool::ReturnUnlockedClients()
     295             : {
     296           0 :   for (auto it = mTextureClientsDeferred.begin(); it != mTextureClientsDeferred.end();) {
     297           0 :     MOZ_ASSERT((*it)->GetReadLock()->AsNonBlockingLock()->GetReadCount() >= 1);
     298             :     // Last count is held by the lock itself.
     299           0 :     if (!(*it)->IsReadLocked()) {
     300           0 :       mTextureClients.push(*it);
     301           0 :       it = mTextureClientsDeferred.erase(it);
     302             : 
     303           0 :       MOZ_ASSERT(mOutstandingClients > 0);
     304           0 :       mOutstandingClients--;
     305             :     } else {
     306           0 :       it++;
     307             :     }
     308             :   }
     309           0 : }
     310             : 
     311             : void
     312           0 : TextureClientPool::ReportClientLost()
     313             : {
     314           0 :   MOZ_ASSERT(mOutstandingClients > mTextureClientsDeferred.size());
     315           0 :   mOutstandingClients--;
     316             :   TCP_LOG("TexturePool %p getting report client lost; down to %u outstanding\n",
     317             :       this, mOutstandingClients);
     318           0 : }
     319             : 
     320             : void
     321           0 : TextureClientPool::Clear()
     322             : {
     323             :   TCP_LOG("TexturePool %p getting cleared\n", this);
     324           0 :   while (!mTextureClients.empty()) {
     325             :     TCP_LOG("TexturePool %p releasing client %p\n",
     326             :         this, mTextureClients.top().get());
     327           0 :     mTextureClients.pop();
     328             :   }
     329           0 :   while (!mTextureClientsDeferred.empty()) {
     330           0 :     MOZ_ASSERT(mOutstandingClients > 0);
     331           0 :     mOutstandingClients--;
     332             :     TCP_LOG("TexturePool %p releasing deferred client %p\n",
     333             :         this, mTextureClientsDeferred.front().get());
     334           0 :     mTextureClientsDeferred.pop_front();
     335             :   }
     336           0 : }
     337             : 
     338           0 : void TextureClientPool::Destroy()
     339             : {
     340           0 :   Clear();
     341           0 :   mDestroyed = true;
     342           0 :   mInitialPoolSize = 0;
     343           0 :   mPoolUnusedSize = 0;
     344           0 : }
     345             : 
     346             : } // namespace layers
     347             : } // namespace mozilla

Generated by: LCOV version 1.13