diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/src/HuiFxEngine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/coretoolkit/src/HuiFxEngine.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,644 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + + +#include "HuiFxEngine.h" +#include "HuiFxEffectParser.h" +#include "HuiFxEffect.h" +#include "HuiFxEffectCache.h" +#include +#include +#include +#include +#include + +#if 0 +_LIT(cache1, "C:\\Data\\drop_shadow.fxml"); +const TDesC *cache_array[]={ &cache1 }; +TInt cache_array_size = sizeof(cache_array)/sizeof(cache_array[0]); +#endif + +EXPORT_C void CHuiFxEngine::ConstructL(THuiFxEngineType aEngineType) + { + iType = aEngineType; + iBuffersInUse = 0; +#ifdef HUIFX_RBCACHE_ENABLED + iBuffersInCache = 0; + // critical to be initialised to zeros: zero indicates an empty entry in array. + memset(iBufferCache, '\0', sizeof(iBufferCache)); +#endif +#ifdef HUIFX_EFFECTCACHE_ENABLED + iCache = CHuiFxEffectCache::NewL(); + +#if 0 + // Preloading cache items + for(int i=0;iFindOrCreateL(node); // moves ownership + CleanupStack::Pop(); + //delete effect; // no need for this effect. + } +#endif +#endif + CHuiStatic::Env().AddMemoryLevelObserver(this); + } + +EXPORT_C TBool CHuiFxEngine::FxmlUsesInput1(const TDesC &aFileName) + { +#ifdef HUIFX_EFFECTCACHE_ENABLED + return iCache->FxmlUsesInput1(aFileName); +#endif +#ifndef HUIFX_EFFECTCACHE_ENABLED + return EFalse; +#endif + } + +EXPORT_C void CHuiFxEngine::RegisterEffectL(const TDesC &aFileName) + { +#ifdef HUIFX_EFFECTCACHE_ENABLED + const TDesC *filename = &aFileName; + if (!BaflUtils::FileExists( CHuiStatic::FsSession(), *filename )) + { + return; + } + CHuiFxEffect *effect = NULL; + TRect extRectI; + TRect *extRect = &extRectI; + CHuiFxEffectCacheEffectNode *node = new(ELeave) CHuiFxEffectCacheEffectNode(*filename, effect, 0, extRect, this); + CleanupStack::PushL(node); + iCache->CreateL(node); // moves ownership + CleanupStack::Pop(); +#endif + } + +#ifdef HUIFX_EFFECTCACHE_ENABLED +EXPORT_C void CHuiFxEngine::UnRegisterEffectL(const TDesC &aFileName) + { + MHuiFxEffectCacheNode *node = iCache->FindDup(aFileName); + if (node) + iCache->UnUse(node); +#else +EXPORT_C void CHuiFxEngine::UnRegisterEffectL(const TDesC &) + { +#endif + } + +EXPORT_C void CHuiFxEngine::LoadEffectL( + const TDesC& aFileName, + CHuiFxEffect*& aEffect, + MHuiEffectable* aVisual, +#ifndef HUIFX_EFFECTCACHE_ENABLED + TRect* extRect, +#else + TRect*, +#endif + MAlfGfxEffectObserver* aEffectEndObserver, + TInt aHandle, + TInt aFlags ) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::LoadEffectL - %S, 0x%x, 0x%x"),&aFileName, aVisual, aEffect ); +#endif + if (aFileName.Length() == 0) + { + User::Leave( KErrNotFound); + } + //TODO: reuse parser? + if( aEffect != NULL ) User::Leave( KErrGeneral ); +#ifndef HUIFX_EFFECTCACHE_ENABLED + iExtRect = TRect(); // clear the extrect + if ( extRect ) + { + iExtRect = *extRect; + } + CHuiFxEffectParser* parser = CHuiFxEffectParser::NewL( *this, aVisual ); + CleanupStack::PushL( parser ); + parser->SetEffectEndObserver( aEffectEndObserver, aHandle ); + parser->SetEffectFlags( aFlags ); + // Parsing is asychronous, but we are not waiting for it to end. + // CHuiFxEffectParser will take care of everything, and CHuiVisual + // will kill the parser when parsing is finished or cancelled. + aVisual->SetEffectParser( parser ); // ownership transferred + CleanupStack::Pop( parser ); + parser->ParseL( aFileName, iExtRect ); +#endif +#ifdef HUIFX_EFFECTCACHE_ENABLED + CHuiFxEffectCacheEffectNode *node = new (ELeave) CHuiFxEffectCacheEffectNode(aFileName, aEffect, aVisual, &iExtRect, this); + node->SetEffectEndObserver( aEffectEndObserver, aHandle ); + aFlags |= KHuiFxDelayRunUntilFirstFrameHasBeenDrawn; + node->SetEffectFlags( aFlags ); + CleanupStack::PushL(node); + iCache->FindOrCreateL(node); // takes ownership + CleanupStack::Pop(); +#endif + } + +EXPORT_C void CHuiFxEngine::LoadGroupEffectL( + const TDesC& aFileName, + CHuiFxEffect*& aEffect, + MHuiEffectable* aVisual, + TInt aGroup, +#ifndef HUIFX_EFFECTCACHE_ENABLED + TRect* extRect, +#else + TRect*, +#endif + MAlfGfxEffectObserver* aEffectEndObserver, + TInt aHandle, + TInt aFlags ) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::LoadEffectL - %S, 0x%x, 0x%x"),&aFileName, aVisual, aEffect ); +#endif + if (aFileName.Length() == 0) + { + User::Leave( KErrNotFound); + } + //TODO: reuse parser? + if( aEffect != NULL ) User::Leave( KErrGeneral ); +#ifndef HUIFX_EFFECTCACHE_ENABLED + iExtRect = TRect(); // clear the extrect + if ( extRect ) + { + iExtRect = *extRect; + } + CHuiFxEffectParser* parser = CHuiFxEffectParser::NewL( *this, aVisual ); + CleanupStack::PushL( parser ); + parser->SetEffectEndObserver( aEffectEndObserver, aHandle ); + parser->SetEffectFlags( aFlags ); + // Parsing is asychronous, but we are not waiting for it to end. + // CHuiFxEffectParser will take care of everything, and CHuiVisual + // will kill the parser when parsing is finished or cancelled. + aVisual->SetEffectParser( parser ); // ownership transferred + CleanupStack::Pop( parser ); + parser->ParseL( aFileName, iExtRect ); +#endif +#ifdef HUIFX_EFFECTCACHE_ENABLED + CHuiFxEffectCacheEffectNode *node = new (ELeave) CHuiFxEffectCacheEffectNode(aFileName, aEffect, aVisual, &iExtRect, this); + node->SetEffectEndObserver( aEffectEndObserver, aHandle ); + if (aGroup != KErrNotFound) + { + aFlags |= KHuiFxWaitGroupSyncronization; + node->SetEffectGroup(aGroup); + } + aFlags |= KHuiFxDelayRunUntilFirstFrameHasBeenDrawn; + node->SetEffectFlags( aFlags ); + + CleanupStack::PushL(node); + iCache->FindOrCreateL(node); // takes ownership + CleanupStack::Pop(); +#endif + } +EXPORT_C CHuiFxEngine::~CHuiFxEngine() + { + iActiveEffects.ResetAndDestroy(); + iActiveEffects.Close(); +#ifdef HUIFX_EFFECTCACHE_ENABLED + delete iCache; +#endif + CHuiStatic::Env().RemoveMemoryLevelObserver(this); + } + +EXPORT_C void CHuiFxEngine::Release() + { + ASSERT(iBuffersInUse == 0); +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::Release - 0x%x"),this); +#endif +#ifdef HUIFX_RBCACHE_ENABLED + int freedBuffers = 0; + for(int i = 0; i < CACHE_SIZE; i++) + { + CHuiFxRenderbuffer *entry = iBufferCache[i]; + if(entry) + { + ReleaseNativeRenderbuffer(entry); + iBufferCache[i] = 0; + freedBuffers++; + } + } + // there should be as many freed buffers as there were free buffers. + ASSERT(freedBuffers == iBuffersInCache); +#endif + } + +EXPORT_C void CHuiFxEngine::RestoreL() + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::RestoreL - 0x%x "), this); +#endif +#ifdef HUIFX_RBCACHE_ENABLED + memset(iBufferCache, '\0', sizeof(iBufferCache)); + iBuffersInCache = 0; +#endif + iBuffersInUse = 0; + } + +void CHuiFxEngine::NotifyEffectEndObservers() + { + for ( TInt i = iActiveEffects.Count() - 1; i >= 0; i-- ) + { + CHuiFxEffect* effect = iActiveEffects[i]; + if (!effect->Changed()) + { + effect->NotifyEffectEndObserver(); + } + } + } + +EXPORT_C void CHuiFxEngine::AdvanceTime(TReal32 aElapsedTime) + { + // TODO: Can we do anything about all this polling? + TInt i; + TBool refreshRequired = EFalse; +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::AdvanceTime - 0x%x "), this); +#endif + // Go through the list in reverse order. +// If the effect has ended, and has the callback set, +// the effect will be removed, and will no longer be part of iActiveEffects set. +// We must check if the effect is still in our list, but the indices change +// if something is removed from the middle of the list + for ( i = iActiveEffects.Count() - 1; i >= 0; i-- ) + { + CHuiFxEffect* effect = iActiveEffects[i]; + if (effect->Changed()) + { + refreshRequired = ETrue; + } + if ( i < iActiveEffects.Count() && effect == iActiveEffects[i] && !(effect->EffectFlags() & KHuiFxWaitGroupSyncronization)) + { + // The effect is still in its place, it did not go away yet + effect->AdvanceTime(aElapsedTime); + } + } + + if (refreshRequired) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::AdvanceTime - manually continue refresh ")); +#endif + CHuiStatic::Env().ContinueRefresh(); + } + } + +EXPORT_C void CHuiFxEngine::AddEffectL(CHuiFxEffect* aEffect) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::AddEffectL - 0x%x "), aEffect); +#endif // #ifdef HUIFX_TRACE + + iActiveEffects.AppendL(aEffect); + } + +EXPORT_C void CHuiFxEngine::RemoveEffect(CHuiFxEffect* aEffect) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::RemoveEffect - 0x%x "), aEffect); +#endif + TInt i = iActiveEffects.Find(aEffect); + if (i >= 0) + { + iActiveEffects.Remove(i); + } + } + +EXPORT_C TReal32 CHuiFxEngine::GetReferenceValue(THuiFxReferencePoint aPoint) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::GetReferenceValue - %d "), aPoint); +#endif + switch (aPoint) + { + case EReferencePointDisplayWidth: + case EReferencePointDisplayRight: + { + CHuiDisplay* display = &CHuiStatic::Env().PrimaryDisplay(); + return display->VisibleArea().Size().iWidth; // was DefaultRenderbuffer()->Size().iWidth + } + case EReferencePointDisplayHeight: + case EReferencePointDisplayBottom: + { + CHuiDisplay* display = &CHuiStatic::Env().PrimaryDisplay(); + return display->VisibleArea().Size().iHeight; // was DefaultRenderbuffer()->Size().iHeight + } + default: + break; + } + // display left and top return 0 + return 0.0f; + } + +EXPORT_C THuiFxEngineType CHuiFxEngine::EngineType() + { + return iType; + } + +EXPORT_C CHuiFxRenderbuffer* CHuiFxEngine::AcquireRenderbuffer(const TSize& aDesiredSize) + { + return AcquireRenderbuffer(aDesiredSize, ETrue); + } + +CHuiFxRenderbuffer* CHuiFxEngine::AcquireRenderbuffer(const TSize& aDesiredSize, TBool aAllowLarger) + { + CHuiFxRenderbuffer *buffer = 0; +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::AcquireRenderbuffer - w: %d h: %d "), aDesiredSize.iWidth, aDesiredSize.iHeight); +#endif + +#ifdef HUIFX_RBCACHE_ENABLED + if(!IsCacheEmpty()) + { + buffer = LookupFreeRenderbuffer(aDesiredSize, aAllowLarger); + } + + if(buffer == 0) // no free or no suitable buffer available --- create new + { +#endif + buffer = AcquireNativeRenderbuffer(aDesiredSize); +#ifdef HUIFX_RBCACHE_ENABLED + if(!IsCacheEmpty()) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::AcquireRenderbuffer() --- no suitable buffer found from cache even if it is populated. Needed buffer size: %dx%d"), aDesiredSize.iWidth, aDesiredSize.iHeight); +#endif + } + } + else + { + buffer->SetPosition(TPoint(0,0)); + buffer->EnableBackground(EFalse); + buffer->PrepareForReuse(aDesiredSize); // clean up the buffer + } +#endif + iBuffersInUse++; +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::AcquireRenderbuffer - buffer 0x%x "), buffer); +#endif + return (CHuiFxRenderbuffer *)buffer; + } + +// try to find a reusable buffer from iFreeBufferList +#ifdef HUIFX_RBCACHE_ENABLED + +CHuiFxRenderbuffer* CHuiFxEngine::LookupFreeRenderbuffer(const TSize& aDesiredSize, TBool aAllowLarger) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::LookupFreeRenderbuffer - w: %d h: %d "), aDesiredSize.iWidth, aDesiredSize.iHeight); +#endif +#ifdef _DEBUG + const int preFreeBuffers = iBuffersInCache; +#endif + CHuiFxRenderbuffer *buffer = 0; + int i; + + for(i = 0; i < CACHE_SIZE; i++) + { + if(iBufferCache[i]) + { + const TSize& bufferSize = iBufferCache[i]->Size(); + + if (aAllowLarger) + { + if ((aDesiredSize.iHeight <= bufferSize.iHeight) && (aDesiredSize.iWidth <= bufferSize.iWidth)) + { + buffer = iBufferCache[i]; + iBufferCache[i] = 0; // mark entry as empty + iBuffersInCache--; + break; // we've found a suitable buffer + } + } + else + { + if ((aDesiredSize.iHeight == bufferSize.iHeight) && (aDesiredSize.iWidth == bufferSize.iWidth)) + { + buffer = iBufferCache[i]; + iBufferCache[i] = 0; // mark entry as empty + iBuffersInCache--; + break; // we've found a suitable buffer + } + + } + } + } + + // sanity check + ASSERT(((buffer != 0) ? (preFreeBuffers == iBuffersInCache + 1) : (preFreeBuffers == iBuffersInCache))); + +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::LookupFreeRenderbuffer - buffer 0x%x "), buffer); +#endif + return buffer; + } +#endif + +EXPORT_C void CHuiFxEngine::ReleaseRenderbuffer(CHuiFxRenderbuffer* aBuffer) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::ReleaseRenderbuffer - buffer: 0x%x "), aBuffer); +#endif + ASSERT((aBuffer) && (iBuffersInUse > 0)); + +#ifdef HUIFX_RBCACHE_ENABLED + if(iLowGraphicsMemoryMode || IsCacheFull()) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::ReleaseRenderbuffer() --- Renderbuffer cache full! Suspectible for memory fragmentation! Cache size is %d entries."), CACHE_SIZE); +#endif +#endif + ReleaseNativeRenderbuffer(aBuffer); + aBuffer = 0; +#ifdef HUIFX_RBCACHE_ENABLED + } + else + { + InsertFreeRenderbuffer(aBuffer); + } +#endif + iBuffersInUse--; + } + +#ifdef HUIFX_RBCACHE_ENABLED +void CHuiFxEngine::InsertFreeRenderbuffer(CHuiFxRenderbuffer* aBuffer) + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::InsertFreeRenderbuffer - buf: 0x%x "), aBuffer); +#endif +#ifdef _DEBUG + const int preiFreeBuffers = iBuffersInCache; +#endif + + ASSERT((aBuffer) && (!IsCacheFull())); + + for(int i = 0; i < CACHE_SIZE; i++) + { + if(iBufferCache[i] == 0) + { + iBufferCache[i] = aBuffer; + iBuffersInCache++; + aBuffer = 0; + break; + } + } + + ASSERT((aBuffer == 0) && (preiFreeBuffers + 1 == iBuffersInCache)); // we have actually inserted the aBuffer into iFreeBufferList successfully? + } + +inline TBool CHuiFxEngine::IsCacheEmpty() const + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::IsCacheEmpty - %d "), (iBuffersInCache == 0)); +#endif + if(iBuffersInCache == 0) + { + return ETrue; + } + else + { + return EFalse; + } + } + +inline TBool CHuiFxEngine::IsCacheFull() const + { +#ifdef HUIFX_TRACE + RDebug::Print(_L("CHuiFxEngine::IsCacheFull - %d "), (iBuffersInCache == CACHE_SIZE)); +#endif + if(iBuffersInCache == CACHE_SIZE) + { + return ETrue; + } + else + { + return EFalse; + } + } +#endif + +EXPORT_C void CHuiFxEngine::EnableLowMemoryState(TBool /*aEnable*/) + { + // deprecated + } + +EXPORT_C void CHuiFxEngine::SetMemoryLevel(THuiMemoryLevel aLevel) + { + iLowGraphicsMemoryMode = aLevel; + if(iLowGraphicsMemoryMode) // != Normal + { + ClearCache(); + } + } + +EXPORT_C void CHuiFxEngine::Composite(CHuiGc& /*aGc*/, CHuiFxRenderbuffer& /*aSource*/, const TPoint& /*aTargetPoint*/, TBool /*aOpaque*/, TInt /*aAlpha*/) + { + // Default implementation does nothing + } + +TInt CHuiFxEngine::LowMemoryState() + { + return iLowGraphicsMemoryMode; + } + +TBool CHuiFxEngine::HasActiveEffects() const + { + return iActiveEffects.Count() > 0; + } + +void CHuiFxEngine::ClearCache() + { + // Release cached render targets from effects + for (TInt j=0; jReleaseCachedRenderTarget(); + } + + if(IsCacheEmpty()) + { + return; + } + else + { + //clear cache + for(TInt i = 0; i < CACHE_SIZE; i++) + { + if(iBufferCache[i] != 0) + { + ReleaseNativeRenderbuffer(iBufferCache[i]); + iBufferCache[i] = 0; + iBuffersInCache--; + } + } + } + + ASSERT(iBuffersInCache == 0); + } + +EXPORT_C void CHuiFxEngine::BeginGroupEffect(TInt aGroup) + { + TInt index = iActiveEffectGroups.Find(aGroup); + if (index == KErrNotFound) + { + iActiveEffectGroups.Append(aGroup); + } + else + { + // group already exists + } + } + +EXPORT_C TInt CHuiFxEngine::ActiveGroupEffect() + { + if (iActiveEffectGroups.Count() > 0) + { + return iActiveEffectGroups[iActiveEffectGroups.Count()-1]; + } + else + { + return KErrNotFound; + } + } + +EXPORT_C void CHuiFxEngine::StartGroupEffect(TInt aGroup) + { + TInt index = iActiveEffectGroups.Find(aGroup); + if (index != KErrNotFound) + { + iActiveEffectGroups.Remove(index); + + for ( TInt i = iActiveEffects.Count() - 1; i >= 0; i-- ) + { + CHuiFxEffect* effect = iActiveEffects[i]; + TInt flags = effect->EffectFlags(); + if ((flags & KHuiFxWaitGroupSyncronization) && (effect->GroupId() == aGroup)) + { + flags &= ~KHuiFxWaitGroupSyncronization; + effect->SetEffectFlags(flags); + } + } + } + }