summaryrefslogtreecommitdiff
path: root/vcl/source/graphic
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2024-03-18 00:17:54 +0900
committerTomaž Vajngerl <quikee@gmail.com>2024-03-30 15:21:10 +0100
commit324f2e135427f2f24cf7eb9a4fab4aa903329ae5 (patch)
treebdcf04a1cd47b22a7612e903f9c68aef17c1dc41 /vcl/source/graphic
parent174430d7a831eede078b6718d991b506d39180f1 (diff)
vcl: change (graphic) Manager into a general memory manager
Graphic memory manager was changes so that it can work with any object that implements a specific interface (MemoryManaged). With this it will be possible to use other objects (that take a lot of memory) to be managed by the manager. It is also a first step to move memory managin responsibilities away from Graphic and move it into the specific objects instead (BitmapEx, Animation and VectorGraphic). Change-Id: I7638bd89a1c9ece5c4bc95b506d2192492894ef3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164958 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl/source/graphic')
-rw-r--r--vcl/source/graphic/Manager.cxx286
1 files changed, 82 insertions, 204 deletions
diff --git a/vcl/source/graphic/Manager.cxx b/vcl/source/graphic/Manager.cxx
index 4bb4ce79534b..fb316aef153d 100644
--- a/vcl/source/graphic/Manager.cxx
+++ b/vcl/source/graphic/Manager.cxx
@@ -26,8 +26,6 @@
using namespace css;
-namespace vcl::graphic
-{
namespace
{
void setupConfigurationValuesIfPossible(sal_Int64& rMemoryLimit,
@@ -51,267 +49,147 @@ void setupConfigurationValuesIfPossible(sal_Int64& rMemoryLimit,
}
}
-Manager& Manager::get()
+namespace vcl::graphic
{
- static Manager gStaticManager;
- return gStaticManager;
-}
-
-Manager::Manager()
- : mnAllowedIdleTime(10)
- , mbSwapEnabled(true)
- , mbReducingGraphicMemory(false)
- , mnMemoryLimit(300000000)
- , mnUsedSize(0)
- , maSwapOutTimer("graphic::Manager maSwapOutTimer")
+MemoryManager::MemoryManager()
+ : maSwapOutTimer("MemoryManager::MemoryManager maSwapOutTimer")
{
setupConfigurationValuesIfPossible(mnMemoryLimit, mnAllowedIdleTime, mbSwapEnabled);
if (mbSwapEnabled)
{
- maSwapOutTimer.SetInvokeHandler(LINK(this, Manager, SwapOutTimerHandler));
- maSwapOutTimer.SetTimeout(10000);
+ maSwapOutTimer.SetInvokeHandler(LINK(this, MemoryManager, ReduceMemoryTimerHandler));
+ maSwapOutTimer.SetTimeout(mnTimeout);
maSwapOutTimer.Start();
}
}
-void Manager::loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
+MemoryManager& MemoryManager::get()
{
- // make a copy of m_pImpGraphicList because if we swap out a svg, the svg
- // filter may create more temp Graphics which are auto-added to
- // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g.
- // reexport of tdf118346-1.odg
- o3tl::sorted_vector<ImpGraphic*> aImpGraphicList = m_pImpGraphicList;
-
- for (ImpGraphic* pEachImpGraphic : aImpGraphicList)
- {
- if (mnUsedSize < sal_Int64(mnMemoryLimit * 0.7) && !bDropAll)
- return;
-
- if (pEachImpGraphic->isSwappedOut())
- continue;
-
- sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic);
- if (nCurrentGraphicSize > 100000 || bDropAll)
- {
- if (!pEachImpGraphic->mpContext)
- {
- auto aCurrent = std::chrono::high_resolution_clock::now();
- auto aDeltaTime = aCurrent - pEachImpGraphic->maLastUsed;
- auto aSeconds = std::chrono::duration_cast<std::chrono::seconds>(aDeltaTime);
-
- if (aSeconds > mnAllowedIdleTime)
- {
- // unlock because svgio can call back into us
- rGuard.unlock();
- pEachImpGraphic->swapOut();
- rGuard.lock();
- }
- }
- }
- }
+ static MemoryManager gStaticManager;
+ return gStaticManager;
}
-void Manager::reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
+IMPL_LINK(MemoryManager, ReduceMemoryTimerHandler, Timer*, pTimer, void)
{
- // maMutex is locked in callers
-
- if (!mbSwapEnabled)
- return;
-
- if (mnUsedSize < mnMemoryLimit && !bDropAll)
- return;
-
- // avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg
- if (mbReducingGraphicMemory)
- return;
-
- mbReducingGraphicMemory = true;
-
- loopGraphicsAndSwapOut(rGuard, bDropAll);
-
- sal_Int64 calculatedSize = 0;
- for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
- {
- if (!pEachImpGraphic->isSwappedOut())
- {
- calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
- }
- }
-
- if (calculatedSize != mnUsedSize)
- {
- assert(rGuard.owns_lock() && rGuard.mutex() == &maMutex);
- // coverity[missing_lock: FALSE] - as above assert
- mnUsedSize = calculatedSize;
- }
-
- mbReducingGraphicMemory = false;
+ std::unique_lock aGuard(maMutex);
+ pTimer->Stop();
+ reduceMemory(aGuard);
+ pTimer->Start();
}
-void Manager::dropCache()
+void MemoryManager::registerObject(MemoryManaged* pMemoryManaged)
{
std::unique_lock aGuard(maMutex);
- reduceGraphicMemory(aGuard, true);
+ // Insert and update the used size (bytes)
+ assert(aGuard.owns_lock() && aGuard.mutex() == &maMutex);
+ // coverity[missing_lock: FALSE] - as above assert
+ mnTotalSize += pMemoryManaged->getCurrentSizeInBytes();
+ maObjectList.insert(pMemoryManaged);
}
-void Manager::dumpState(rtl::OStringBuffer& rState)
+void MemoryManager::unregisterObject(MemoryManaged* pMemoryManaged)
{
std::unique_lock aGuard(maMutex);
+ mnTotalSize -= pMemoryManaged->getCurrentSizeInBytes();
+ maObjectList.erase(pMemoryManaged);
+}
- rState.append("\nImage Manager items:\t");
- rState.append(static_cast<sal_Int32>(m_pImpGraphicList.size()));
- rState.append("\tsize:\t");
- rState.append(static_cast<sal_Int64>(mnUsedSize / 1024));
- rState.append("\tkb");
+void MemoryManager::changeExisting(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize)
+{
+ std::scoped_lock aGuard(maMutex);
+ sal_Int64 nOldSize = pMemoryManaged->getCurrentSizeInBytes();
+ mnTotalSize -= nOldSize;
+ mnTotalSize += nNewSize;
+ pMemoryManaged->setCurrentSizeInBytes(nNewSize);
+}
- for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
- {
- pEachImpGraphic->dumpState(rState);
- }
+void MemoryManager::swappedIn(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize)
+{
+ changeExisting(pMemoryManaged, nNewSize);
}
-sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic)
+void MemoryManager::swappedOut(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize)
{
- if (!pImpGraphic->isAvailable())
- return 0;
- return pImpGraphic->getSizeBytes();
+ changeExisting(pMemoryManaged, nNewSize);
}
-IMPL_LINK(Manager, SwapOutTimerHandler, Timer*, pTimer, void)
+void MemoryManager::reduceAllAndNow()
{
std::unique_lock aGuard(maMutex);
-
- pTimer->Stop();
- reduceGraphicMemory(aGuard);
- pTimer->Start();
+ reduceMemory(aGuard, true);
}
-void Manager::registerGraphic(const std::shared_ptr<ImpGraphic>& pImpGraphic)
+void MemoryManager::dumpState(rtl::OStringBuffer& rState)
{
std::unique_lock aGuard(maMutex);
- // make some space first
- if (mnUsedSize > mnMemoryLimit)
- reduceGraphicMemory(aGuard);
-
- // Insert and update the used size (bytes)
- assert(aGuard.owns_lock() && aGuard.mutex() == &maMutex);
- // coverity[missing_lock: FALSE] - as above assert
- mnUsedSize += getGraphicSizeBytes(pImpGraphic.get());
- m_pImpGraphicList.insert(pImpGraphic.get());
-
- // calculate size of the graphic set
- sal_Int64 calculatedSize = 0;
- for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
- {
- if (!pEachImpGraphic->isSwappedOut())
- {
- calculatedSize += getGraphicSizeBytes(pEachImpGraphic);
- }
- }
+ rState.append("\nMemory Manager items:\t");
+ rState.append(static_cast<sal_Int32>(maObjectList.size()));
+ rState.append("\tsize:\t");
+ rState.append(static_cast<sal_Int64>(mnTotalSize / 1024));
+ rState.append("\tkb");
- if (calculatedSize != mnUsedSize)
+ for (MemoryManaged* pMemoryManaged : maObjectList)
{
- SAL_INFO_IF(calculatedSize != mnUsedSize, "vcl.gdi",
- "Calculated size mismatch. Variable size is '"
- << mnUsedSize << "' but calculated size is '" << calculatedSize << "'");
- mnUsedSize = calculatedSize;
+ pMemoryManaged->dumpState(rState);
}
}
-void Manager::unregisterGraphic(ImpGraphic* pImpGraphic)
+void MemoryManager::reduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
{
- std::scoped_lock aGuard(maMutex);
-
- mnUsedSize -= getGraphicSizeBytes(pImpGraphic);
- m_pImpGraphicList.erase(pImpGraphic);
-}
+ // maMutex is locked in callers
-std::shared_ptr<ImpGraphic> Manager::copy(std::shared_ptr<ImpGraphic> const& rImpGraphicPtr)
-{
- auto pReturn = std::make_shared<ImpGraphic>(*rImpGraphicPtr);
- registerGraphic(pReturn);
- return pReturn;
-}
+ if (!mbSwapEnabled)
+ return;
-std::shared_ptr<ImpGraphic> Manager::newInstance()
-{
- auto pReturn = std::make_shared<ImpGraphic>();
- registerGraphic(pReturn);
- return pReturn;
-}
+ if (mnTotalSize < mnMemoryLimit && !bDropAll)
+ return;
-std::shared_ptr<ImpGraphic> Manager::newInstance(std::shared_ptr<GfxLink> const& rGfxLink,
- sal_Int32 nPageIndex)
-{
- auto pReturn = std::make_shared<ImpGraphic>(rGfxLink, nPageIndex);
- registerGraphic(pReturn);
- return pReturn;
-}
+ // avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg
+ if (mbReducingGraphicMemory)
+ return;
-std::shared_ptr<ImpGraphic> Manager::newInstance(const BitmapEx& rBitmapEx)
-{
- auto pReturn = std::make_shared<ImpGraphic>(rBitmapEx);
- registerGraphic(pReturn);
- return pReturn;
-}
+ mbReducingGraphicMemory = true;
-std::shared_ptr<ImpGraphic> Manager::newInstance(const Animation& rAnimation)
-{
- auto pReturn = std::make_shared<ImpGraphic>(rAnimation);
- registerGraphic(pReturn);
- return pReturn;
-}
+ loopAndReduceMemory(rGuard, bDropAll);
-std::shared_ptr<ImpGraphic>
-Manager::newInstance(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr)
-{
- auto pReturn = std::make_shared<ImpGraphic>(rVectorGraphicDataPtr);
- registerGraphic(pReturn);
- return pReturn;
+ mbReducingGraphicMemory = false;
}
-std::shared_ptr<ImpGraphic> Manager::newInstance(const GDIMetaFile& rMetaFile)
+void MemoryManager::loopAndReduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
{
- auto pReturn = std::make_shared<ImpGraphic>(rMetaFile);
- registerGraphic(pReturn);
- return pReturn;
-}
+ // make a copy of m_pImpGraphicList because if we swap out a svg, the svg
+ // filter may create more temp Graphics which are auto-added to
+ // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g.
+ // reexport of tdf118346-1.odg
-std::shared_ptr<ImpGraphic> Manager::newInstance(const GraphicExternalLink& rGraphicLink)
-{
- auto pReturn = std::make_shared<ImpGraphic>(rGraphicLink);
- registerGraphic(pReturn);
- return pReturn;
-}
+ o3tl::sorted_vector<MemoryManaged*> aObjectListCopy = maObjectList;
-void Manager::swappedIn(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
-{
- std::scoped_lock aGuard(maMutex);
- if (pImpGraphic)
+ for (MemoryManaged* pMemoryManaged : aObjectListCopy)
{
- mnUsedSize += nSizeBytes;
- }
-}
+ if (!pMemoryManaged->canReduceMemory())
+ continue;
-void Manager::swappedOut(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes)
-{
- std::scoped_lock aGuard(maMutex);
- if (pImpGraphic)
- {
- mnUsedSize -= nSizeBytes;
+ sal_Int64 nCurrentSizeInBytes = pMemoryManaged->getCurrentSizeInBytes();
+ if (nCurrentSizeInBytes > mnSmallFrySize || bDropAll) // ignore small-fry
+ {
+ auto aCurrent = std::chrono::high_resolution_clock::now();
+ auto aDeltaTime = aCurrent - pMemoryManaged->getLastUsed();
+ auto aSeconds = std::chrono::duration_cast<std::chrono::seconds>(aDeltaTime);
+
+ if (aSeconds > mnAllowedIdleTime)
+ {
+ // unlock because svgio can call back into us
+ rGuard.unlock();
+ pMemoryManaged->reduceMemory();
+ rGuard.lock();
+ }
+ }
}
}
-void Manager::changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSizeBytes)
-{
- std::scoped_lock aGuard(maMutex);
-
- mnUsedSize -= nOldSizeBytes;
- mnUsedSize += getGraphicSizeBytes(pImpGraphic);
-}
} // end vcl::graphic
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */