Add LRU cache of rendered bitmaps, to improve redraw performance in the absence of graphics HW support for OpenVG PDK_3.0.f
authorWilliam Roberts <williamr@symbian.org>
Thu, 07 Jan 2010 12:19:27 +0000
changeset 20 f6fd4830a02c
parent 19 57ed406024d5
child 24 c9fe84c7602b
Add LRU cache of rendered bitmaps, to improve redraw performance in the absence of graphics HW support for OpenVG
uigraphics/NVGRenderStage/src/nvgrenderstage.cpp
uigraphics/NVGRenderStage/src/nvgrenderstage.h
--- a/uigraphics/NVGRenderStage/src/nvgrenderstage.cpp	Fri Jan 29 16:56:39 2010 +0000
+++ b/uigraphics/NVGRenderStage/src/nvgrenderstage.cpp	Thu Jan 07 12:19:27 2010 +0000
@@ -20,11 +20,22 @@
 #include <AknIconHeader.h>
 #include <AknIconUtils.h>
 
+TCachedConversion::TCachedConversion() :
+  iLink(), iCachedResult(NULL)
+  {}
+
+TCachedConversion::~TCachedConversion()
+  {
+  delete iCachedResult;
+  }
 
 const TUid KUidNvgExtendedBitmap = {0x39b9273e};  
 
 CNvgRenderStage::CNvgRenderStage() : 	
-	iExtendedBitmapError(KErrNone)
+	iExtendedBitmapError(KErrNone), 
+	iCache(_FOFF(TCachedConversion,iLink)), 
+	iCacheIterator(iCache),
+	iCacheFree(MAX_NVG_CACHE_SIZE)
 	{	
 	}
 
@@ -46,8 +57,6 @@
 	
 void CNvgRenderStage::ConstructL(CWsRenderStage* aNextStage)
 	{
-	iBmp = new(ELeave) CFbsBitmap;	
-	iMaskBmp = new(ELeave) CFbsBitmap;	
 	iBrushPattern = new(ELeave) CFbsBitmap;
 	iInternalBrushPattern = new(ELeave) CFbsBitmap;
 	iGraphicsInterface = new(ELeave) CVGIGraphicsInterface;
@@ -61,12 +70,18 @@
 CNvgRenderStage::~CNvgRenderStage()
 	{	
 	iEmptyRegion.Close();
-	delete iBmp;
-	delete iMaskBmp;	
 	delete iBrushPattern;
 	delete iInternalBrushPattern;
 	delete iNvgEngine;
 	delete iGraphicsInterface;
+	
+	iCacheIterator.SetToFirst();
+  TCachedConversion* cached = iCacheIterator++;
+	while (cached != NULL)
+	 {
+   delete cached;
+   cached = iCacheIterator++;
+   }
 	}
 
 /** The only interface returned by this render stage is MWsGraphicsContext.
@@ -156,15 +171,14 @@
 	{
 	if (iGc)
 		{
+		CFbsBitmap* sourceBitmap = const_cast<CFbsBitmap*>(&aSourceBitmap);
+		
 		if (aSourceBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
-			{			
-			TRect destRect(TPoint(aDestPos.iX,aDestPos.iY), aSourceBitmap.SizeInPixels());			
-			DrawExtendedBitmap(*iGc, destRect, aSourceBitmap);				
+			{						
+			sourceBitmap = GetConvertedBitmap(aSourceBitmap);
 			}
-		else
-			{
-			iGc->BitBlt(aDestPos, aSourceBitmap);
-			}
+		
+		iGc->BitBlt(aDestPos, *sourceBitmap);
 		}
 	}
 
@@ -178,15 +192,14 @@
 	{
 	if (iGc)
 		{			
+		CFbsBitmap* sourceBitmap = const_cast<CFbsBitmap*>(&aSourceBitmap);
+		
 		if (aSourceBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
-			{		
-			TRect destRect(TPoint(aDestPos.iX,aDestPos.iY), aSourceRect.Size()); 		
-			DrawExtendedBitmap(*iGc, destRect, aSourceBitmap);	
+			{						
+			sourceBitmap = GetConvertedBitmap(aSourceBitmap);
 			}
-		else
-			{
-			iGc->BitBlt(aDestPos, aSourceBitmap, aSourceRect);
-			}
+
+		iGc->BitBlt(aDestPos, *sourceBitmap, aSourceRect);
 		}
 	}
 
@@ -205,14 +218,12 @@
 		
 		if (aSourceBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{						
-			CopyExtendedBitmapToNormalBitmap(aSourceBitmap, *iBmp); 		
-			sourceBitmap = iBmp;
+			sourceBitmap = GetConvertedBitmap(aSourceBitmap);
 			}
 		
 		if (aMaskBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{			
-			CopyExtendedBitmapToNormalBitmap(aMaskBitmap, *iMaskBmp); 		
-			maskBitmap = iMaskBmp;
+			maskBitmap = GetConvertedBitmap(aMaskBitmap);
 			}	
 		
 		iGc->BitBltMasked(aDestPos, *sourceBitmap, aSourceRect, *maskBitmap, aInvertMask);
@@ -234,14 +245,12 @@
 		
 		if (aSourceBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{
-			CopyExtendedBitmapToNormalBitmap(aSourceBitmap, *iBmp); 		
-			sourceBitmap = iBmp;
+			sourceBitmap = GetConvertedBitmap(aSourceBitmap);
 			}
 		
 		if (aMaskBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{
-			CopyExtendedBitmapToNormalBitmap(aMaskBitmap, *iMaskBmp); 		
-			maskBitmap = iMaskBmp;
+			maskBitmap = GetConvertedBitmap(aMaskBitmap);
 			}	
 		
 		iGc->BitBltMasked(aDestPos, *sourceBitmap, aSourceRect, *maskBitmap, aMaskPos);
@@ -332,8 +341,7 @@
 		
 		if (aSourceBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{
-			CopyExtendedBitmapToNormalBitmap(aSourceBitmap, *iBmp); 
-			sourceBitmap = iBmp;
+			sourceBitmap = GetConvertedBitmap(aSourceBitmap);
 			}
 				
 		iGc->DrawBitmap(aDestRect, *sourceBitmap);	
@@ -354,8 +362,7 @@
 		
 		if (aSourceBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{
-			CopyExtendedBitmapToNormalBitmap(aSourceBitmap, *iBmp); 
-			sourceBitmap = iBmp;
+			sourceBitmap = GetConvertedBitmap(aSourceBitmap);
 			}
 				
 		iGc->DrawBitmap(aDestRect, *sourceBitmap, aSourceRect);		
@@ -377,13 +384,11 @@
 		
 		if (aSourceBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{
-			CopyExtendedBitmapToNormalBitmap(aSourceBitmap, *iBmp); 
-			sourceBitmap = iBmp;
+			sourceBitmap = GetConvertedBitmap(aSourceBitmap);
 			}
 		if (aMaskBitmap.ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{
-			CopyExtendedBitmapToNormalBitmap(aMaskBitmap, *iMaskBmp);	
-			maskBitmap = iMaskBmp;
+			maskBitmap = GetConvertedBitmap(aMaskBitmap);
 			}
 	
 		iGc->DrawBitmapMasked(aDestRect, *sourceBitmap, aSourceRect, *maskBitmap, aInvertMask);
@@ -783,7 +788,7 @@
 		iBrushPattern->Duplicate(aFbsBitmapHandle);
 		if (iBrushPattern->ExtendedBitmapType() == KUidNvgExtendedBitmap)
 			{
-			CopyExtendedBitmapToNormalBitmap(*iBrushPattern, *iInternalBrushPattern);
+			iInternalBrushPattern = GetConvertedBitmap(*iBrushPattern);
 			iGc->SetBrushPattern(*iInternalBrushPattern);
 			}
 		else
@@ -984,36 +989,92 @@
 		}
 	}
 
-/** Helper method used by BitBlt() and DrawBitmap() 
+
+/** Helper method that draws an NVG extended bitmap into a normal bitmap. 
 
-@param aGc The graphics context to draw the extended bitmap to.
-@param aDestRect The rectangle that the source bitmap will be drawn to.
-@param aSourceBitmap The extended bitmap of type 0x39b9273e to be drawn.
+@param aExtendedBitmapSrc The extended bitmap to draw 
+
+@pre aExtendedBitmapSrc must be an extended bitmap of extended bitmap type 0x39b9273e
+ */
 
-@pre aSourceBitmap must be an extended bitmap of type 0x39b9273e.
-@post Sets an error that can be retrieved using GetError() is an error occurs. 
- */
-void CNvgRenderStage::DrawExtendedBitmap(MWsGraphicsContext& aGc, const TRect& aDestRect, const CFbsBitmap& aSourceBitmap)
-	{
-  CopyExtendedBitmapToNormalBitmap(aSourceBitmap, *iBmp); 		
-  aGc.BitBlt(aDestRect.iTl, *iBmp);
-	}
+CFbsBitmap* CNvgRenderStage::GetConvertedBitmap(const CFbsBitmap& aExtendedBitmapSrc)
+  {
+  aExtendedBitmapSrc.BeginDataAccess();
+  const TUint8* bmpData = (const TUint8*)aExtendedBitmapSrc.DataAddress();
+
+  TPtr8 IconHeaderPtr((TUint8*)bmpData, KIconHeaderLength, KIconHeaderLength);
+  TAknIconHeader iconheader(IconHeaderPtr);
 
-/** Helper method used by BitBlt() and DrawBitmap()
-
-@param aGc The graphics context to draw the extended bitmap to.
-@param aDestRect The rectangle that the source bitmap will be drawn to.
-@param aSourceBitmap The extended bitmap of type 0x39b9273e to be drawn.
+  TUint32 bitmapid = iconheader.GetBitmapId();
+  TUint32 handle = aExtendedBitmapSrc.Handle();
+  aExtendedBitmapSrc.EndDataAccess();
+  CFbsBitmap* error = const_cast<CFbsBitmap*>(&aExtendedBitmapSrc);  // not renderable, but better than panic!
+  
+  // look to see if we have this in the cache
+  iCacheIterator.SetToFirst();
+  TCachedConversion* cached = iCacheIterator++;
+  while (cached != NULL)
+    {
+    if (cached->iBitmapID == bitmapid && cached->iDiscriminator == handle)
+      {
+      // Cache hit
+#ifdef DEBUG_NVG_RENDERSTAGE
+      RDebug::Printf("NVG Render cache hit for id %08x, handle %d\n", bitmapid, handle);
+#endif
+      cached->Deque();
+      iCache.AddFirst(*cached);  // move to front of the list, to record use
+      return cached->iCachedResult;  
+      }
+    cached = iCacheIterator++;
+    }
+  
+  // missed in the cache, need to perform the conversion
+  TInt err = KErrNone;
+  if (iCacheFree > 0)
+    {
+    // just allocate a new entry, which will be added to the end
+    TRAP(err, cached = new(ELeave) TCachedConversion);
+    if (err != KErrNone)
+      {
+      return error;
+      }
+    TRAP(err, cached->iCachedResult = new(ELeave) CFbsBitmap);
+    if (err != KErrNone)
+      {
+      delete cached;
+      return error;
+      }
+    }
+  else
+    {
+    // Remove the least recently used item
+    cached = iCache.Last();
+    cached->Deque();  // remove from the cache
+    iCacheFree++;
+#ifdef DEBUG_NVG_RENDERSTAGE
+    RDebug::Printf("NVG Render cache removing id %08x, handle %d\n", cached->iBitmapID, cached->iDiscriminator);
+#endif
+    }
+  
+  // cached is now available to hold the new result
+  cached->iBitmapID = bitmapid;
+  cached->iDiscriminator = handle;
 
-@pre aSourceBitmap must be an extended bitmap of type 0x39b9273e.
-@post Sets an error that can be retrieved using GetError() is an error occurs. 
- */
-void CNvgRenderStage::DrawExtendedBitmap(CFbsBitGc& aGc, const TRect& aDestRect, const CFbsBitmap& aSourceBitmap)
-	{
-  CopyExtendedBitmapToNormalBitmap(aSourceBitmap, *iBmp); 		
-  aGc.BitBlt(aDestRect.iTl, iBmp);
-	}
-
+  CopyExtendedBitmapToNormalBitmap(aExtendedBitmapSrc, *cached->iCachedResult);
+  if (iExtendedBitmapError != KErrNone)
+    {
+    delete cached;
+    return error;
+    }
+  
+  // Newly cached bitmap is valid
+  iCache.AddFirst(*cached);
+  iCacheFree--;
+#ifdef DEBUG_NVG_RENDERSTAGE
+  RDebug::Printf("NVG Render cache added id %08x, handle %d (%d free)\n", bitmapid, handle, iCacheFree);
+#endif
+  return cached->iCachedResult;
+  }
 
 /** Helper method that draws an NVG extended bitmap into a normal bitmap. The normal
 bitmap passed is resized before the extended bitmap is drawn into it.
@@ -1024,6 +1085,7 @@
 @pre aExtendedBitmapSrc must be an extended bitmap of extended bitmap type 0x39b9273e
 @post aBitmapDest has been reset and resized and now contains a representation of the aExtendedBitmapSrc
  */
+
 void CNvgRenderStage::CopyExtendedBitmapToNormalBitmap(const CFbsBitmap& aExtendedBitmapSrc, CFbsBitmap& aBitmapDst)
 	{
 	TSize size = aExtendedBitmapSrc.SizeInPixels();
@@ -1053,6 +1115,10 @@
   TPtr8 IconHeaderPtr((TUint8*)bmpData, KIconHeaderLength, KIconHeaderLength);
   TAknIconHeader iconheader(IconHeaderPtr);
 
+#ifdef DEBUG_NVG_RENDERSTAGE
+  RDebug::Printf("ConvertExtendedBitmap: id=%08x size (%d x %d)\n", iconheader.GetBitmapId(), size.iWidth, size.iHeight);
+#endif
+
   TInt dataSize = aExtendedBitmapSrc.DataSize();
   // skip TNVGIconHeader structure - we only know about version 0
   if (bmpData[2] == 0)
--- a/uigraphics/NVGRenderStage/src/nvgrenderstage.h	Fri Jan 29 16:56:39 2010 +0000
+++ b/uigraphics/NVGRenderStage/src/nvgrenderstage.h	Thu Jan 07 12:19:27 2010 +0000
@@ -28,13 +28,28 @@
 #include <nvg.h>
 #include "vgigraphicsinterface.h"
 
+/** Struct to form a simple LRU cache of conversion results
+ */
+class TCachedConversion
+  {
+public:
+  TCachedConversion();
+  ~TCachedConversion();
+  inline void Deque();
+  
+public:
+  TDblQueLink iLink;
+  TUint32 iBitmapID;
+  TUint32 iDiscriminator;
+  CFbsBitmap* iCachedResult;
+  };
 
-/** This is a test render stage used for integration testing extended bitmaps of  
-type 0x10285A78. This particular type of extended bitmap was created to test the 
-extended bitmap APIs added to CFbsBitGc (CreateExtendedBitmap(), ExtendedBitmapType() 
-and DataSize()) and also to test the extended bitmap rasterizer interface, CFbsRasterizer.
-The proprietary data contained in an extended bitmap of type 0x10285A78 defines
-the colours and stripe direction of a tricolour flag. 
+void TCachedConversion::Deque() {iLink.Deque();}
+
+/** This is a render stage used for processing NVG Icon bitmaps in the absence of
+graphics acceleration hardware. The software implementation of OpenVG is used to
+render the NVG drawing commands onto a normal CFbsBitmap, and a simple LRU cache
+is used to keep the results for faster redrawing.
 
 This render stage implements the MWsGraphicsContext interface so that it can intercept
 any drawing commands that draw an extended bitmap, any commands that draw a normal 
@@ -131,22 +146,28 @@
 	
 private:
 	// Helper methods that support the implementation of MWsGraphicsContext
-	void DrawExtendedBitmap(MWsGraphicsContext& aGc, const TRect& aDestRect, const CFbsBitmap& aSourceBitmap);
-	void DrawExtendedBitmap(CFbsBitGc& aGc, const TRect& aDestRect, const CFbsBitmap& aSourceBitmap);
+	CFbsBitmap* GetConvertedBitmap(const CFbsBitmap& aSourceBitmap);
 	void CopyExtendedBitmapToNormalBitmap(const CFbsBitmap& aExtendedBitmapSrc, CFbsBitmap& aBitmapDst);
-	
+
 private:
 	MWsGraphicsContext* iGc;	
 	TInt iExtendedBitmapError;
 	TPoint iOrigin;
 	RRegion iEmptyRegion;
-	CFbsBitmap* iBmp;
-	CFbsBitmap* iMaskBmp;	
 	CFbsBitmap* iBrushPattern;
 	CFbsBitmap* iInternalBrushPattern;
 	MWsGraphicsContext::TBrushStyle iBrushStyle;
 	CVGIGraphicsInterface* iGraphicsInterface;
 	CNvgEngine* iNvgEngine;
+	
+	// LRU Cache of rendered bitmaps
+#define MAX_NVG_CACHE_SIZE 128
+
+	TDblQue<TCachedConversion> iCache;
+  TDblQueIter<TCachedConversion> iCacheIterator;
+	TUint iCacheFree;
 	};
 
+// #define DEBUG_NVG_RENDERSTAGE
+
 #endif // NVGRENDERSTAGE_H