Kaydet (Commit) 0ca0202a authored tarafından Armin Le Grand's avatar Armin Le Grand Kaydeden (comit) Caolán McNamara

Resolves: #i125111# limit mem footprint for GraphicObjects...

in 32Bit environments

Conflicts:
	svtools/inc/svtools/grfmgr.hxx
	svtools/source/graphic/grfmgr.cxx
	svtools/source/graphic/grfmgr2.cxx
	sw/source/core/doc/notxtfrm.cxx
	sw/source/core/graphic/ndgrf.cxx

"commit 62b0eaf3
 Related: fdo#50697 reset the cache timeout on GetGraphic

 so the graphic gets swapped out Xms after the last use and not Xms after
 initial creation regardless of if it got used a moment earlier."

corrected place for stl sort function for linux

(cherry picked from commit a48414a3)

Conflicts:
	svtools/source/graphic/grfmgr2.cxx

Change-Id: I79158b7d42629f8dec2bc5565540701bcd3ef6f4
6f21c7fd4d2681446fc1a6d9607366a1e69165a1
üst 146c2e00
...@@ -175,6 +175,10 @@ private: ...@@ -175,6 +175,10 @@ private:
Timer* mpSwapOutTimer; Timer* mpSwapOutTimer;
GrfSimpleCacheObj* mpSimpleCache; GrfSimpleCacheObj* mpSimpleCache;
sal_uLong mnAnimationLoopCount; sal_uLong mnAnimationLoopCount;
// a unique increasing ID to be able to say which data change is older
sal_uLong mnDataChangeTimeStamp;
bool mbAutoSwapped : 1; bool mbAutoSwapped : 1;
bool mbTransparent : 1; bool mbTransparent : 1;
bool mbAnimated : 1; bool mbAnimated : 1;
...@@ -299,8 +303,12 @@ private: ...@@ -299,8 +303,12 @@ private:
DECL_LINK( ImplAutoSwapOutHdl, void* ); DECL_LINK( ImplAutoSwapOutHdl, void* );
void SVT_DLLPRIVATE ResetCacheTimeOut(); // restart SwapOut timer; this is like touching in a cache to reset to the full timeout value
void SVT_DLLPRIVATE restartSwapOutTimer() const;
// Handle evtl. needed AfterDataChanges, needs to be called when new
// graphic data is swapped in/added to the GraphicManager
void SVT_DLLPRIVATE ImplAfterDataChange();
protected: protected:
virtual void GraphicManagerDestroyed(); virtual void GraphicManagerDestroyed();
...@@ -506,6 +514,9 @@ public: ...@@ -506,6 +514,9 @@ public:
double fTopCrop, double fTopCrop,
double fRightCrop, double fRightCrop,
double fBottomCrop) const; double fBottomCrop) const;
// read access
sal_uLong GetDataChangeTimeStamp() const { return mnDataChangeTimeStamp; }
}; };
typedef ::std::vector< GraphicObject* > GraphicObjectList_impl; typedef ::std::vector< GraphicObject* > GraphicObjectList_impl;
...@@ -597,12 +608,21 @@ private: ...@@ -597,12 +608,21 @@ private:
OString SVT_DLLPRIVATE ImplGetUniqueID( const GraphicObject& rObj ) const; OString SVT_DLLPRIVATE ImplGetUniqueID( const GraphicObject& rObj ) const;
// This method allows to check memory footprint for all currently swapped in GraphicObjects on this GraphicManager
// which are based on Bitmaps. This is needed on 32Bit systems and only does something on those systems. The problem
// to solve is that normally the SwapOut is timer-driven, but even with short timer settings there are situations
// where this does not trigger - or in other words: A maximum limitation for GraphicManagers was not in place before.
// For 32Bit systems this leads to situations where graphics will be missing. This method will actively swap out
// the longest swapped in graphics until a maximum memory boundary (derived from user settings in tools/options/memory)
// is no longer exceeded
void SVT_DLLPRIVATE ImplCheckSizeOfSwappedInGraphics();
public: public:
GraphicManager( sal_uLong nCacheSize = 10000000UL, sal_uLong nMaxObjCacheSize = 2400000UL ); GraphicManager( sal_uLong nCacheSize = 10000000UL, sal_uLong nMaxObjCacheSize = 2400000UL );
~GraphicManager(); ~GraphicManager();
void SetMaxCacheSize( sal_uLong nNewCacheSize ); void SetMaxCacheSize( sal_uLong nNewCacheSize );
sal_uLong GetMaxCacheSize() const;
void SetMaxObjCacheSize( void SetMaxObjCacheSize(
sal_uLong nNewMaxObjSize, sal_uLong nNewMaxObjSize,
......
...@@ -59,6 +59,19 @@ struct GrfSimpleCacheObj ...@@ -59,6 +59,19 @@ struct GrfSimpleCacheObj
TYPEINIT1_AUTOFACTORY( GraphicObject, SvDataCopyStream ); TYPEINIT1_AUTOFACTORY( GraphicObject, SvDataCopyStream );
// unique increasing ID for being able to detect the GraphicObject with the
// oldest last data changes
static sal_uLong aIncrementingTimeOfLastDataChange = 1;
void GraphicObject::ImplAfterDataChange()
{
// set unique timestamp ID of last data change
mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++;
// check memory footprint of all GraphicObjects managed and evtl. take action
GetGraphicManager().ImplCheckSizeOfSwappedInGraphics();
}
GraphicObject::GraphicObject( const GraphicManager* pMgr ) : GraphicObject::GraphicObject( const GraphicManager* pMgr ) :
maLink (), maLink (),
maUserData () maUserData ()
...@@ -130,6 +143,9 @@ void GraphicObject::ImplConstruct() ...@@ -130,6 +143,9 @@ void GraphicObject::ImplConstruct()
mbAutoSwapped = false; mbAutoSwapped = false;
mbIsInSwapIn = false; mbIsInSwapIn = false;
mbIsInSwapOut = false; mbIsInSwapOut = false;
// Init with a unique, increasing ID
mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++;
} }
void GraphicObject::ImplAssignGraphicData() void GraphicObject::ImplAssignGraphicData()
...@@ -243,6 +259,9 @@ void GraphicObject::ImplAutoSwapIn() ...@@ -243,6 +259,9 @@ void GraphicObject::ImplAutoSwapIn()
if( !mbAutoSwapped && mpMgr ) if( !mbAutoSwapped && mpMgr )
mpMgr->ImplGraphicObjectWasSwappedIn( *this ); mpMgr->ImplGraphicObjectWasSwappedIn( *this );
} }
// Handle evtl. needed AfterDataChanges
ImplAfterDataChange();
} }
} }
...@@ -744,15 +763,6 @@ void GraphicObject::StopAnimation( OutputDevice* pOut, long nExtraData ) ...@@ -744,15 +763,6 @@ void GraphicObject::StopAnimation( OutputDevice* pOut, long nExtraData )
mpSimpleCache->maGraphic.StopAnimation( pOut, nExtraData ); mpSimpleCache->maGraphic.StopAnimation( pOut, nExtraData );
} }
void GraphicObject::ResetCacheTimeOut()
{
if (mpSwapOutTimer)
{
mpSwapOutTimer->Stop();
mpSwapOutTimer->Start();
}
}
const Graphic& GraphicObject::GetGraphic() const const Graphic& GraphicObject::GetGraphic() const
{ {
GraphicObject *pThis = const_cast<GraphicObject*>(this); GraphicObject *pThis = const_cast<GraphicObject*>(this);
...@@ -763,7 +773,7 @@ const Graphic& GraphicObject::GetGraphic() const ...@@ -763,7 +773,7 @@ const Graphic& GraphicObject::GetGraphic() const
//fdo#50697 If we've been asked to provide the graphic, then reset //fdo#50697 If we've been asked to provide the graphic, then reset
//the cache timeout to start from now and not remain at the //the cache timeout to start from now and not remain at the
//time of creation //time of creation
pThis->ResetCacheTimeOut(); pThis->restartSwapOutTimer();
return maGraphic; return maGraphic;
} }
...@@ -785,6 +795,9 @@ void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pC ...@@ -785,6 +795,9 @@ void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pC
if( mpSwapOutTimer ) if( mpSwapOutTimer )
mpSwapOutTimer->Start(); mpSwapOutTimer->Start();
// Handle evtl. needed AfterDataChanges
ImplAfterDataChange();
} }
void GraphicObject::SetGraphic( const Graphic& rGraphic, const OUString& rLink ) void GraphicObject::SetGraphic( const Graphic& rGraphic, const OUString& rLink )
...@@ -1101,7 +1114,9 @@ bool GraphicObject::SwapIn() ...@@ -1101,7 +1114,9 @@ bool GraphicObject::SwapIn()
bRet = true; bRet = true;
} }
else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) )
{
bRet = true; bRet = true;
}
else else
{ {
bRet = maGraphic.SwapIn(); bRet = maGraphic.SwapIn();
...@@ -1111,8 +1126,13 @@ bool GraphicObject::SwapIn() ...@@ -1111,8 +1126,13 @@ bool GraphicObject::SwapIn()
} }
if( bRet ) if( bRet )
{
ImplAssignGraphicData(); ImplAssignGraphicData();
// Handle evtl. needed AfterDataChanges
ImplAfterDataChange();
}
return bRet; return bRet;
} }
...@@ -1297,4 +1317,14 @@ basegfx::B2DVector GraphicObject::calculateCropScaling( ...@@ -1297,4 +1317,14 @@ basegfx::B2DVector GraphicObject::calculateCropScaling(
return basegfx::B2DVector(fFactorX,fFactorY); return basegfx::B2DVector(fFactorX,fFactorY);
} }
// restart SwapOut timer
void GraphicObject::restartSwapOutTimer() const
{
if( mpSwapOutTimer && mpSwapOutTimer->IsActive() )
{
mpSwapOutTimer->Stop();
mpSwapOutTimer->Start();
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -64,6 +64,11 @@ void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize ) ...@@ -64,6 +64,11 @@ void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize )
mpCache->SetMaxDisplayCacheSize( nNewCacheSize ); mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
} }
sal_uLong GraphicManager::GetMaxCacheSize() const
{
return mpCache->GetMaxDisplayCacheSize();
}
void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, bool bDestroyGreaterCached ) void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, bool bDestroyGreaterCached )
{ {
mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached ); mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
...@@ -171,9 +176,81 @@ OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const ...@@ -171,9 +176,81 @@ OString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
return mpCache->GetUniqueID( rObj ); return mpCache->GetUniqueID( rObj );
} }
namespace
{
struct simpleSortByDataChangeTimeStamp
{
bool operator() (GraphicObject* p1, GraphicObject* p2) const
{
return p1->GetDataChangeTimeStamp() < p2->GetDataChangeTimeStamp();
}
};
} // end of anonymous namespace
void GraphicManager::ImplCheckSizeOfSwappedInGraphics()
{
// only necessary for 32bit systems
if(SAL_TYPES_SIZEOFPOINTER <= 4)
{
// get the currently used memory footprint of all swapped in bitmap graphics
// of this graphic manager. Remember candidates in a vector. The size in bytes is
// already available, thus this loop is not expensive to execute
sal_uLong nUsedSize(0);
GraphicObject* pObj = 0;
std::vector< GraphicObject* > aCandidates;
for (size_t i = 0, n = maObjList.size(); i < n; ++i)
{
pObj = maObjList[i];
if (pObj->meType == GRAPHIC_BITMAP && !pObj->IsSwappedOut() && pObj->GetSizeBytes())
{
aCandidates.push_back(pObj);
nUsedSize += pObj->GetSizeBytes();
}
}
// detect maximum allowed memory footprint. Use the user-settings of MaxCacheSize (defaulted
// to 20MB) and add a decent multiplicator (expecrimented to find one). Limit to
// a useful maximum for 32Bit address space
// default is 20MB, so allow 200MB initially
static sal_uLong aMultiplicator(10);
// max at 500MB; I experimented with 800 for debug and 750 for non-debug settings (pics start
// missing when office reaches a mem footprint of 1.5GB) but some secure left over space for
// app activity is needed
static sal_uLong aMaxSize32Bit(500 * 1024 * 1024);
// calc max allowed cache size
const sal_uLong nMaxCacheSize(::std::min(GetMaxCacheSize() * aMultiplicator, aMaxSize32Bit));
if(nUsedSize >= nMaxCacheSize && !aCandidates.empty())
{
// if we use more currently, sort by last DataChangeTimeStamp
// sort by DataChangeTimeStamp so that the oldest get removed first
::std::sort(aCandidates.begin(), aCandidates.end(), simpleSortByDataChangeTimeStamp());
for(sal_uInt32 a(0); nUsedSize >= nMaxCacheSize && a < aCandidates.size(); a++)
{
// swap out until we have no more or the goal to use less than nMaxCacheSize
// is reached
pObj = aCandidates[a];
const sal_uLong nSizeBytes(pObj->GetSizeBytes());
// do not swap out when we have less than 16KB data objects
if(nSizeBytes >= (16 * 1024))
{
pObj->FireSwapOutRequest();
nUsedSize = (nSizeBytes < nUsedSize) ? nUsedSize - nSizeBytes : 0;
}
}
}
}
}
bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
{ {
return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) ); return mpCache->FillSwappedGraphicObject(rObj, rSubstitute);
} }
void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj ) void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
......
...@@ -453,35 +453,43 @@ Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlph ...@@ -453,35 +453,43 @@ Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlph
if(pRetval) if(pRetval)
{ {
sal_uInt8* pSrcRGB(pRGB->mpBits); if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap
sal_uInt8* pSrcA(pA->mpBits);
const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
const Gdiplus::Rect aAllRect(0, 0, nW, nH);
Gdiplus::BitmapData aGdiPlusBitmapData;
pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
// copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
// A from alpha, so inner loop is needed (who invented BitmapEx..?)
for(sal_uInt32 y(0); y < nH; y++)
{ {
const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1); sal_uInt8* pSrcRGB(pRGB->mpBits);
sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride); sal_uInt8* pSrcA(pA->mpBits);
const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
const Gdiplus::Rect aAllRect(0, 0, nW, nH);
Gdiplus::BitmapData aGdiPlusBitmapData;
pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
for(sal_uInt32 x(0); x < nW; x++) // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
// A from alpha, so inner loop is needed (who invented BitmapEx..?)
for(sal_uInt32 y(0); y < nH; y++)
{ {
*targetPixels++ = *pSrcRGB++; const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
*targetPixels++ = *pSrcRGB++; sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride);
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = 0xff - *pSrcA++; for(sal_uInt32 x(0); x < nW; x++)
{
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = 0xff - *pSrcA++;
}
pSrcRGB += nExtraRGB;
pSrcA += nExtraA;
} }
pSrcRGB += nExtraRGB; pRetval->UnlockBits(&aGdiPlusBitmapData);
pSrcA += nExtraA; }
else
{
delete pRetval;
pRetval = NULL;
} }
pRetval->UnlockBits(&aGdiPlusBitmapData);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment