Author: alg Date: Mon Jun 23 16:45:11 2014 New Revision: 1604874 URL: http://svn.apache.org/r1604874 Log: i125111 limit mem footprint for GraphicObjects in 32Bit environments
Modified: openoffice/branches/AOO410/main/ (props changed) openoffice/branches/AOO410/main/svtools/inc/svtools/grfmgr.hxx openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr.cxx openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr2.cxx openoffice/branches/AOO410/main/sw/source/core/doc/notxtfrm.cxx openoffice/branches/AOO410/main/sw/source/core/graphic/ndgrf.cxx openoffice/branches/AOO410/main/vcl/win/source/gdi/salbmp.cxx Propchange: openoffice/branches/AOO410/main/ ------------------------------------------------------------------------------ Merged /openoffice/trunk/main:r1603941,1604028 Modified: openoffice/branches/AOO410/main/svtools/inc/svtools/grfmgr.hxx URL: http://svn.apache.org/viewvc/openoffice/branches/AOO410/main/svtools/inc/svtools/grfmgr.hxx?rev=1604874&r1=1604873&r2=1604874&view=diff ============================================================================== --- openoffice/branches/AOO410/main/svtools/inc/svtools/grfmgr.hxx (original) +++ openoffice/branches/AOO410/main/svtools/inc/svtools/grfmgr.hxx Mon Jun 23 16:45:11 2014 @@ -207,7 +207,10 @@ private: Timer* mpSwapOutTimer; GrfSimpleCacheObj* mpSimpleCache; sal_uLong mnAnimationLoopCount; - void* mpDummy1; + + // a unique increasing ID to be able to say which data change is older + sal_uLong mnDataChangeTimeStamp; + void* mpDummy2; sal_Bool mbAutoSwapped : 1; sal_Bool mbTransparent : 1; @@ -299,6 +302,10 @@ private: DECL_LINK( ImplAutoSwapOutHdl, void* ); + // Handle evtl. needed AfterDataChanges, needs to be called when new + // graphic data is swapped in/added to the GraphicManager + void ImplAfterDataChange(); + protected: virtual void GraphicManagerDestroyed(); @@ -481,6 +488,12 @@ public: double fTopCrop, double fRightCrop, double fBottomCrop) const; + + // read access + sal_uLong GetDataChangeTimeStamp() const { return mnDataChangeTimeStamp; } + + // restart SwapOut timer; this is like touching in a cache to reset to the full timeout value + void restartSwapOutTimer() const; }; // ------------------ @@ -545,6 +558,15 @@ private: ByteString 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 ImplCheckSizeOfSwappedInGraphics(); + public: GraphicManager( sal_uLong nCacheSize = 10000000UL, sal_uLong nMaxObjCacheSize = 2400000UL ); Modified: openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr.cxx URL: http://svn.apache.org/viewvc/openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr.cxx?rev=1604874&r1=1604873&r2=1604874&view=diff ============================================================================== --- openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr.cxx (original) +++ openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr.cxx Mon Jun 23 16:45:11 2014 @@ -76,6 +76,19 @@ struct GrfSimpleCacheObj 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 ) : @@ -173,6 +186,9 @@ void GraphicObject::ImplConstruct() mbAutoSwapped = sal_False; mbIsInSwapIn = sal_False; mbIsInSwapOut = sal_False; + + // Init with a unique, increasing ID + mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++; } // ----------------------------------------------------------------------------- @@ -290,6 +306,9 @@ void GraphicObject::ImplAutoSwapIn() if( !mbAutoSwapped && mpMgr ) mpMgr->ImplGraphicObjectWasSwappedIn( *this ); } + + // Handle evtl. needed AfterDataChanges + ImplAfterDataChange(); } } @@ -914,6 +933,9 @@ void GraphicObject::SetGraphic( const Gr if( mpSwapOutTimer ) mpSwapOutTimer->Start(); + + // Handle evtl. needed AfterDataChanges + ImplAfterDataChange(); } // ----------------------------------------------------------------------------- @@ -1255,7 +1277,9 @@ sal_Bool GraphicObject::SwapIn() bRet = sal_True; } else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) + { bRet = sal_True; + } else { bRet = maGraphic.SwapIn(); @@ -1265,8 +1289,13 @@ sal_Bool GraphicObject::SwapIn() } if( bRet ) + { ImplAssignGraphicData(); + // Handle evtl. needed AfterDataChanges + ImplAfterDataChange(); + } + return bRet; } @@ -1282,7 +1311,9 @@ sal_Bool GraphicObject::SwapIn( SvStream bRet = sal_True; } else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) + { bRet = sal_True; + } else { bRet = maGraphic.SwapIn( pIStm ); @@ -1292,8 +1323,13 @@ sal_Bool GraphicObject::SwapIn( SvStream } if( bRet ) + { ImplAssignGraphicData(); + // + ImplAfterDataChange(); + } + return bRet; } @@ -1453,4 +1489,15 @@ basegfx::B2DVector GraphicObject::calcul return basegfx::B2DVector(fFactorX,fFactorY); } +// ------------------------------------------------------------------------ +// restart SwapOut timer + +void GraphicObject::restartSwapOutTimer() const +{ + if( mpSwapOutTimer && mpSwapOutTimer->IsActive() ) + { + mpSwapOutTimer->Start(); + } +} + // eof Modified: openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr2.cxx URL: http://svn.apache.org/viewvc/openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr2.cxx?rev=1604874&r1=1604873&r2=1604874&view=diff ============================================================================== --- openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr2.cxx (original) +++ openoffice/branches/AOO410/main/svtools/source/graphic/grfmgr2.cxx Mon Jun 23 16:45:11 2014 @@ -258,7 +258,7 @@ sal_Bool GraphicManager::DrawObj( Output bRet = rCached = sal_True; } } - + return bRet; } @@ -267,7 +267,7 @@ sal_Bool GraphicManager::DrawObj( Output void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute, const ByteString* pID, const GraphicObject* pCopyObj ) { - maObjList.Insert( (void*) &rObj, LIST_APPEND ); + maObjList.Insert( (void*) &rObj, LIST_APPEND ); mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj ); } @@ -295,16 +295,89 @@ ByteString GraphicManager::ImplGetUnique // ----------------------------------------------------------------------------- +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(pObj = (GraphicObject*)maObjList.First(); pObj; pObj = (GraphicObject*)maObjList.Next()) + { + 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 AOO 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; + } + } + } + } +} + +// ----------------------------------------------------------------------------- + sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) { - return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) ); + return mpCache->FillSwappedGraphicObject(rObj, rSubstitute); } // ----------------------------------------------------------------------------- void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj ) { - mpCache->GraphicObjectWasSwappedIn( rObj ); + mpCache->GraphicObjectWasSwappedIn( rObj ); } // ----------------------------------------------------------------------------- Modified: openoffice/branches/AOO410/main/sw/source/core/doc/notxtfrm.cxx URL: http://svn.apache.org/viewvc/openoffice/branches/AOO410/main/sw/source/core/doc/notxtfrm.cxx?rev=1604874&r1=1604873&r2=1604874&view=diff ============================================================================== --- openoffice/branches/AOO410/main/sw/source/core/doc/notxtfrm.cxx (original) +++ openoffice/branches/AOO410/main/sw/source/core/doc/notxtfrm.cxx Mon Jun 23 16:45:11 2014 @@ -1006,6 +1006,9 @@ void SwNoTxtFrm::PaintPicture( OutputDev aContent, aTargetRange, aTargetRange); + + // need to reset the timer manually (was in original paints at GraphicManager) + rGrfObj.restartSwapOutTimer(); } } else Modified: openoffice/branches/AOO410/main/sw/source/core/graphic/ndgrf.cxx URL: http://svn.apache.org/viewvc/openoffice/branches/AOO410/main/sw/source/core/graphic/ndgrf.cxx?rev=1604874&r1=1604873&r2=1604874&view=diff ============================================================================== --- openoffice/branches/AOO410/main/sw/source/core/graphic/ndgrf.cxx (original) +++ openoffice/branches/AOO410/main/sw/source/core/graphic/ndgrf.cxx Mon Jun 23 16:45:11 2014 @@ -58,14 +58,36 @@ #include <retrieveinputstreamconsumer.hxx> #include <drawinglayer/processor2d/objectinfoextractor2d.hxx> #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx> +#include <unotools/cacheoptions.hxx> using namespace com::sun::star; +#define SWAPGRAPHIC_TIMEOUT 5000 -// As Writer graphics are no longer painted via the graphic manager - see <SwNoTxtFrm::PaintPicture(..)> - -// it is needed to swap out the Writer graphics automatically after a certain amount of time. -// --> 5000ms -#define TIMETOSWAPOUTGRAPHICAUTOMATICALLY 5000 +// For comments see same method used in svx +sal_uInt32 getCacheTimeInMs() +{ + static bool bSetAtAll(true); + + if(bSetAtAll) + { + static bool bSetToPreferenceTime(true); + + if(bSetToPreferenceTime) + { + const SvtCacheOptions aCacheOptions; + const sal_Int32 nSeconds(aCacheOptions.GetGraphicManagerObjectReleaseTime()); + + return nSeconds * 1000 / 12; + } + else + { + return SWAPGRAPHIC_TIMEOUT; + } + } + + return 0; +} // -------------------- // SwGrfNode @@ -83,7 +105,7 @@ SwGrfNode::SwGrfNode( mbLinkedInputStreamReady( false ), mbIsStreamReadOnly( sal_False ) { - maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), TIMETOSWAPOUTGRAPHICAUTOMATICALLY ); + maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), getCacheTimeInMs() ); bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = bFrameInPaint = bScaleImageMap = sal_False; bGrafikArrived = sal_True; @@ -102,7 +124,7 @@ SwGrfNode::SwGrfNode( mbIsStreamReadOnly( sal_False ) { maGrfObj = rGrfObj; - maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), TIMETOSWAPOUTGRAPHICAUTOMATICALLY ); + maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), getCacheTimeInMs() ); if ( rGrfObj.HasUserData() && rGrfObj.IsSwappedOut() ) maGrfObj.SetSwapState(); bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = bFrameInPaint = bScaleImageMap = sal_False; @@ -125,7 +147,7 @@ SwGrfNode::SwGrfNode( mbLinkedInputStreamReady( false ), mbIsStreamReadOnly( sal_False ) { - maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), TIMETOSWAPOUTGRAPHICAUTOMATICALLY ); + maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), getCacheTimeInMs() ); Graphic aGrf; aGrf.SetDefaultType(); Modified: openoffice/branches/AOO410/main/vcl/win/source/gdi/salbmp.cxx URL: http://svn.apache.org/viewvc/openoffice/branches/AOO410/main/vcl/win/source/gdi/salbmp.cxx?rev=1604874&r1=1604873&r2=1604874&view=diff ============================================================================== --- openoffice/branches/AOO410/main/vcl/win/source/gdi/salbmp.cxx (original) +++ openoffice/branches/AOO410/main/vcl/win/source/gdi/salbmp.cxx Mon Jun 23 16:45:11 2014 @@ -448,35 +448,43 @@ Gdiplus::Bitmap* WinSalBitmap::ImplCreat if(pRetval) { - sal_uInt8* pSrcRGB(pRGB->mpBits); - 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++) + if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap { - const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1); - sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride); - - for(sal_uInt32 x(0); x < nW; x++) + sal_uInt8* pSrcRGB(pRGB->mpBits); + 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++) { - *targetPixels++ = *pSrcRGB++; - *targetPixels++ = *pSrcRGB++; - *targetPixels++ = *pSrcRGB++; - *targetPixels++ = 0xff - *pSrcA++; + const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1); + sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride); + + for(sal_uInt32 x(0); x < nW; x++) + { + *targetPixels++ = *pSrcRGB++; + *targetPixels++ = *pSrcRGB++; + *targetPixels++ = *pSrcRGB++; + *targetPixels++ = 0xff - *pSrcA++; + } + + pSrcRGB += nExtraRGB; + pSrcA += nExtraA; } - pSrcRGB += nExtraRGB; - pSrcA += nExtraA; + pRetval->UnlockBits(&aGdiPlusBitmapData); + } + else + { + delete pRetval; + pRetval = NULL; } - - pRetval->UnlockBits(&aGdiPlusBitmapData); } }