Add MMP files to build libOpenVG_sw.lib which uses LINKAS to redirect to libOpenVG.dll (and
the same for libEGL_sw.lib and libOpenVGU_sw.lib).
Only the libEGL_sw.lib redirection isn't activated - this can't happen until there is a merged
libEGL.dll which supports the OpenWF synchronisation and also implements the graphical support functions.
The overall aim is to eliminate the *_sw.dll implementations, at least as a compile-time way of choosing
a software-only implementation.The correct way to choose is to put the right set of libraries into a ROM
with suitable renaming, and in the emulator to use the "switching DLL" technique to pick the right set.
As the Symbian Foundation doesn't have any alternative implementations, we don't need the switching DLLs
and we can build directly to the correct name.
// Copyright (c) 2008-2009 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: Owns, hides, and provides an interface to the OpenWFC compositor for use by the final (display) render stage.
#include "openwfcwrapper.h"
#include "panic.h"
#include "utils.h"
#include <WF/wfc.h>
#include "elementwrapper.h"
#include <graphics/compositionsurfaceupdate.h>
#include <graphics/symbianstream.h>
#include "openwfcpanics.h"
#include "openwfcjobmanager.h"
#include <graphics/eglsynchelper.h>
#define KRgbaBlack 0x000000FF
void Panic(TOpenWfcPanic aPanic)
{
_LIT(KPanic, "OpenWFC");
User::Panic(KPanic, aPanic);
}
class COpenWfcWrapper::OffScreenComposeGuard
{
public:
OffScreenComposeGuard(TRequestStatus*& aRequestStatus);
void SetOffScreenNativeStream(WFCNativeStreamType aNativeStream);
void SetTargetNativeStream(WFCNativeStreamType aNativeStream);
void SetSync(EGLSyncKHR aSync, EGLDisplay aDpy);
void SetDeviceAndContext(WFCDevice aDevice, WFCContext aContext);
void Close();
void LogRequestStatusError(TInt aRequestStatusError);
private:
TRequestStatus*& iRequestStatus;
EGLSyncKHR iSync;
EGLDisplay iEGLDisplay;
WFCDevice iDevice;
WFCContext iContext;
TInt iRequestStatusError;
};
COpenWfcWrapper::OffScreenComposeGuard::OffScreenComposeGuard(TRequestStatus*& aRequestStatus):
iRequestStatus(aRequestStatus),
iSync(EGL_NO_SYNC_KHR),
iDevice(WFC_INVALID_HANDLE),
iContext(WFC_INVALID_HANDLE),
iRequestStatusError(KErrNone)
{}
void COpenWfcWrapper::OffScreenComposeGuard::SetSync(EGLSyncKHR aSync, EGLDisplay aDpy)
{
iSync = aSync;
iEGLDisplay = aDpy;
}
void COpenWfcWrapper::OffScreenComposeGuard::SetDeviceAndContext(WFCDevice aDevice, WFCContext aContext)
{
iContext = aContext;
iDevice = aDevice;
}
void COpenWfcWrapper::OffScreenComposeGuard::LogRequestStatusError(TInt aRequestStatusError)
{
iRequestStatusError=aRequestStatusError;
}
void COpenWfcWrapper::OffScreenComposeGuard::Close()
{
if (iContext != WFC_INVALID_HANDLE)
{
DestroyAllContextElements(iDevice, iContext);
wfcDestroyContext(iDevice, iContext);
}
if (iSync != EGL_NO_SYNC_KHR)
{
eglDestroySyncKHR(iEGLDisplay, iSync);
}
if (iRequestStatus)
{
User::RequestComplete(iRequestStatus, iRequestStatusError);
}
}
TEMPLATE_SPECIALIZATION class RHashTableBase::Defaults<TSurfaceId, RHashTableBase::EDefaultSpecifier_Normal>
{
public:
inline static TGeneralHashFunction32 Hash();
inline static TGeneralIdentityRelation Id();
};
inline TGeneralHashFunction32 RHashTableBase::Defaults<TSurfaceId, RHashTableBase::EDefaultSpecifier_Normal>::Hash()
{return (TGeneralHashFunction32)&DefaultHash::Integer;}
inline TGeneralIdentityRelation RHashTableBase::Defaults<TSurfaceId, RHashTableBase::EDefaultSpecifier_Normal>::Id()
{return (TGeneralIdentityRelation)&DefaultIdentity::Integer;}
TUint32 COpenWfcWrapper::HashFunction(const TSurfaceId& aHashKey)
{
TPckgC<TSurfaceId> pckg(aHashKey);
return DefaultHash::Des8(pckg);
}
COpenWfcWrapper* COpenWfcWrapper::NewL(TInt aScreenNo, CDisplayPolicy* aDisplayPolicy)
{
COpenWfcWrapper* wrapper = new (ELeave) COpenWfcWrapper(aDisplayPolicy);
CleanupStack::PushL(wrapper);
wrapper->ConstructL(aScreenNo);
CleanupStack::Pop(wrapper);
return wrapper;
}
COpenWfcWrapper::COpenWfcWrapper(CDisplayPolicy* aDisplayPolicy)
: iUiSurface(TSurfaceId::CreateNullId()), iDisplayPolicy(aDisplayPolicy),
iSourceMap(THashFunction32<TSurfaceId>(COpenWfcWrapper::HashFunction), TIdentityRelation<TSurfaceId>()),
iDevice(WFC_INVALID_HANDLE),
iOnScreenContext(WFC_INVALID_HANDLE),
iScreenNumber(-1),
iJobManager(NULL),
iRotation(MWsScene::ESceneAntiClockwise0),
iAutonomousCompositionInitiated(EFalse)
{
}
void COpenWfcWrapper::ConstructL(TInt aScreenId)
{
#ifdef _DEBUG
_LIT(KOpenWfcLog, "+ COpenWfcWrapper::ConstructL");
RDebug::Print(KOpenWfcLog);
#endif
iScreenNumber = aScreenId;
WFCint filterList[] = { WFC_DEVICE_FILTER_SCREEN_NUMBER, iScreenNumber, WFC_NONE};
iEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(iEGLDisplay, NULL, NULL);
WFCint dev = 0;
if ((wfcEnumerateDevices(&dev, 1, filterList) == 1) &&
(dev != WFC_INVALID_HANDLE))
{
// clean previous errors
wfcGetError(iDevice);
// Let's get the device handle, opening in the same time the device
iDevice = wfcCreateDevice(dev, NULL);
if (iDevice==NULL)
{
//Not enough information to deduce why the device could not be created. Report as memory failure
User::Leave(KErrNoMemory);
}
//Can't clean previous errors until we have a device, and the errors should be none if it created successfully.
OPENWFC_ASSERT_DEBUG(!wfcGetError(iDevice),EPanicWfcStartupErrorUnexpected);
iOnScreenContext = wfcCreateOnScreenContext(iDevice, iScreenNumber, NULL);
if (iOnScreenContext==NULL)
{
TInt err = wfcGetError(iDevice);
OPENWFC_ASSERT_DEBUG(err==WFC_ERROR_OUT_OF_MEMORY,EPanicWfcContextNotCreated);
User::Leave((err==WFC_ERROR_OUT_OF_MEMORY)?KErrNoMemory:KErrUnknown);
}
wfcSetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION, WFC_ROTATION_0);
wfcSetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_BG_COLOR, KRgbaBlack);
iContextDisplayControl = NULL;
User::LeaveIfNull(iJobManager = COpenWfcJobManger::NewL(*this, iDevice, iOnScreenContext, iScreenNumber));
}
else
{
// we cannot continue because we cannot find a device for the given screenId
// Not enough information to get detailed error! Report as parameter not accepted.
User::Leave(KErrArgument);
}
iSurfaceManager.Open();
iSourceMap.Reserve(iInitialSourceMapSize);
}
COpenWfcWrapper::~COpenWfcWrapper()
{
iUiElement1 = NULL;
iUiElement2 = NULL;
if(!iUiSurface.IsNull())
UnregisterSurface(iUiSurface);
if (iJobManager)
{
PauseComposition();
delete iJobManager;
}
//destroy all the elements, which should remove all the element references.
while (iCleanupElementList)
{
CElementWrapper* cleanupElement = iCleanupElementList;
delete cleanupElement;
OPENWFC_ASSERT_DEBUG(cleanupElement != iCleanupElementList,EPanicWfcElementNotRemovedOnShutdown);
if (cleanupElement == iCleanupElementList)
{
break; //can't keep cleaning up the same front item
}
}
THashMapIter<TSurfaceId, SourceAndRef> iter(iSourceMap);
const TSurfaceId* nextKey = iter.NextKey();
while (nextKey)
{
const SourceAndRef* pSource = NULL;
//destroy any remaining registered surfaces
pSource = iter.CurrentValue();
OPENWFC_ASSERT_DEBUG(pSource && pSource->elementRef == 0,EPanicWfcElementNotRemovedOnShutdown);
wfcDestroySource(iDevice,pSource->source);
nextKey = iter.NextKey();
}
iSourceMap.Close();
iSurfaceManager.Close();
eglTerminate(iEGLDisplay);
// Destroying the context should take care of any sources or masks
wfcDestroyContext(iDevice, iOnScreenContext);
wfcDestroyDevice(iDevice);
}
class CBaseExtension: public CBase
{
public:
virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
{ return CBase::Extension_(aExtensionId,a0,a1); }
};
TInt COpenWfcWrapper::Extension_(TUint aExtensionId, TAny*& aRetPtr, TAny* aExtra)
{
#ifndef _DEBUG
(void) aExtra;
#endif
switch (aExtensionId)
{
#ifdef _DEBUG
case EExtensionDebugBackendGuid:
return KErrNotSupported;
case EExtensionDebugContextGuid:
aRetPtr=(TAny*)OnScreenContext();
return KErrNone;
case EExtensionDebugDeviceGuid:
aRetPtr=(TAny*)Device();
return KErrNone;
case EExtensionDebugElementGuid:
if (aExtra)
{
CElementWrapper* newElement=static_cast<CElementWrapper*>(aExtra);
aRetPtr=(TAny*)newElement->Element();
return KErrNone;
}
else
{
return KErrBadHandle;
}
case EExtensionDebugSourceGuid:
if (aExtra)
{
TSurfaceId* surfId=static_cast<TSurfaceId*>(aExtra);
SourceAndRef* foundSourceAndRef=iSourceMap.Find(*surfId);
if (foundSourceAndRef)
{
aRetPtr=(TAny*)foundSourceAndRef->source;
return KErrNone;
}
else
{
return KErrNotFound;
}
}
else
{
return KErrBadHandle;
}
#endif
case MCompositionSurfaceUpdate::ETypeId:
{
CBaseExtension* basePtr = NULL;
SymbianStreamHasRegisteredScreenNotifications(iScreenNumber,reinterpret_cast<void**>(&basePtr));
if (basePtr)
{
return basePtr->Extension_(MCompositionSurfaceUpdate::KUidCompositionSurfaceUpdate,aRetPtr,aExtra);
}
else
{
return KErrNotSupported;
}
}
case MWsDisplayControl::ETypeId:
if (iContextDisplayControl)
{
aRetPtr= static_cast<MWsDisplayControl*>(this);
return KErrNone;
}
else
{
return KErrNotSupported;
}
case MDisplayControlBase::ETypeId:
if (iContextDisplayControl)
{
aRetPtr= static_cast<MDisplayControlBase*>(this);
return KErrNone;
}
else
{
return KErrNotSupported;
}
default:
return KErrNotSupported;
}
}
MWsElement* COpenWfcWrapper::CreateElementL()
{
CElementWrapper* element = CElementWrapper::NewL(*this,iCleanupElementList);
return element;
}
void COpenWfcWrapper::DestroyElement(MWsElement* aElement)
{
if(aElement)
{
CElementWrapper* element=static_cast<CElementWrapper*>(aElement);
RemoveElementFromSceneList(element);
if (!(element->UpdateFlags()&CElementWrapper::EUpdate_SceneCommited))
{
delete element;
}
}
}
void COpenWfcWrapper::Compose(TRequestStatus* aCompleted)
{
STD_ASSERT_DEBUG(CompositionDue(), EPluginPanicCompositionSequenceError);
OPENWFC_ASSERT_DEBUG(iJobManager, EPanicWfcThreadManagerNotInitialised);
if (!iAutonomousCompositionInitiated)
{
ResumeComposition();
}
iJobManager->ComposeRequest(aCompleted);
iCompositionModified = EFalse;
ResumeCompositorIfPaused();
}
TSize COpenWfcWrapper::ScreenSize() const
{
// clean previous errors
#ifdef _DEBUG
(void)wfcGetError(iDevice);
#endif
TInt height = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_TARGET_HEIGHT);
OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
TInt width = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_TARGET_WIDTH);
OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
WFCint rotation = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION);
OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
return rotation == WFC_ROTATION_0 || rotation == WFC_ROTATION_180 ? TSize(width, height) : TSize(height, width);
}
TInt COpenWfcWrapper::RegisterSurface (const TSurfaceId& aSurface)
{
// clean previous errors
wfcGetError(iDevice);
//check surface id not null
if (aSurface.IsNull())
{
return KErrArgument;
}
if (!IsValidSurface(aSurface))
{
return KErrBadHandle;
}
//look for surface being registered
SourceAndRef* sourceAndRef = iSourceMap.Find(aSurface);
if (sourceAndRef)
{
//if registered increase ref count and return
sourceAndRef->sourceRef++;
return KErrNone;
}
// Surface not currently registered so do so now.
// Initialise struct. Could be handled via. constructor.
SourceAndRef newSourceAndRef;
newSourceAndRef.source = NULL;
newSourceAndRef.sourceRef = 1; //Surface reference count
newSourceAndRef.elementRef = 0; //Element reference count
//No need to acquire stream as public NativeStream handle is TSurfaceId
WFCNativeStreamType stream = reinterpret_cast<WFCNativeStreamType>(&aSurface);
//create source
newSourceAndRef.source = wfcCreateSourceFromStream(iDevice,iOnScreenContext,stream,NULL);
//check for valid surface size should be performed by compositor in CreateSource.
if (newSourceAndRef.source == WFC_INVALID_HANDLE)
{
return TranslateOpenWfcError(wfcGetError(iDevice));
}
//add to list
TInt err = iSourceMap.Insert(aSurface,newSourceAndRef);
if (err != KErrNone)
{
wfcDestroySource(iDevice,newSourceAndRef.source);
return KErrNoMemory;
}
return KErrNone;
}
TInt COpenWfcWrapper::UnregisterSurface (const TSurfaceId& aSurface)
{
//check surface id not null
if (aSurface.IsNull())
{
return KErrArgument;
}
if (!IsValidSurface(aSurface))
{
return KErrArgument;
}
SourceAndRef* sourceAndRef = iSourceMap.Find(aSurface);
if (sourceAndRef && sourceAndRef->sourceRef == 0)
{
sourceAndRef = NULL;
}
if (sourceAndRef)
{
if (sourceAndRef->sourceRef <= 1)
{
sourceAndRef->sourceRef = 0;
if (sourceAndRef->elementRef > 0)
{
//if elements are currently in use
return KErrInUse;
}
wfcDestroySource(iDevice,sourceAndRef->source); //removing source reference on the stream
//destroy entry
iSourceMap.Remove(aSurface);
return KErrNone;
}
sourceAndRef->sourceRef--;
return KErrNone;
}
return KErrBadHandle;
}
TBool COpenWfcWrapper::IsValidSurface(const TSurfaceId& aSurface)
{
if (aSurface.Type() != TSurfaceId::EScreenSurface)
{
RSurfaceManager::TInfoBuf buff;
TInt err = SurfaceManager().SurfaceInfo(aSurface, buff);
if (err == KErrArgument)
{
return EFalse;
}
}
return ETrue;
}
/**
* Finds the source for a registered surface ID and increments its "element" reference count
* @return registered source handle or WFC_INVALID_HANDLE if not registered
**/
WFCSource COpenWfcWrapper::IncEltRefRegSource(const TSurfaceId& aHashKey)
{
SourceAndRef* foundSourceAndRef=iSourceMap.Find(aHashKey);
if (foundSourceAndRef && foundSourceAndRef->sourceRef)
{ //still registered
foundSourceAndRef->elementRef++;
return foundSourceAndRef->source;
}
return WFC_INVALID_HANDLE;
}
/**
* Finds the source for a registered surface ID and decrements the "element" reference count.
* If all counts are zero then the source is unregistered and the mapping removed
* @return positive if not destroyed, 0 if destroyed
* or KErrBadHandle if bad surface id or surface has no element reference count
**/
TInt COpenWfcWrapper::DecEltRefRegSource(const TSurfaceId& aHashKey)
{
SourceAndRef* foundSourceAndRef=iSourceMap.Find(aHashKey);
if (foundSourceAndRef && foundSourceAndRef->elementRef>0)
{
TInt retRefs=((--foundSourceAndRef->elementRef)+foundSourceAndRef->sourceRef);
if (retRefs==0)
{
wfcDestroySource(iDevice,foundSourceAndRef->source);
iSourceMap.Remove(aHashKey);
}
return retRefs;
}
return KErrBadHandle;
}
void COpenWfcWrapper::RemoveElement(MWsElement* aElement)
{
if (!aElement)
{
return;
}
CElementWrapper* removeElement = static_cast<CElementWrapper*>(aElement);
//the UI element is a special case since we set and maintain the surface
TUint32 renderStageFlags;
removeElement->GetRenderStageFlags(renderStageFlags);
if (renderStageFlags & MWsElement::EElementIsIndirectlyRenderedUserInterface ||
renderStageFlags & MWsElement::EElementIsDirectlyRenderedUserInterface)
{
if(removeElement == iUiElement1)
iUiElement1 = NULL;
else if(removeElement == iUiElement2)
iUiElement2 = NULL;
else
STD_ASSERT_DEBUG(EFalse, EPluginPanicNonMatchingRemovalOfUiElement);
}
RemoveElementFromSceneList(removeElement);
removeElement->InsertAfter(iRemoveElementList,NULL,CElementWrapper::EUpdate_Remove); //insert into remove element list!!!
SetCompositionModified();
}
void COpenWfcWrapper::RemoveElementFromSceneList(CElementWrapper* aElement)
{
CElementWrapper** refFromElementBelow=NULL;
if (iSceneElementList==aElement)
{
refFromElementBelow=&iSceneElementList; //remove from bottom of scene
}
else if (iRemoveElementList==aElement)
{
refFromElementBelow=&iRemoveElementList;
}
else
{
refFromElementBelow=aElement->RefsMyElementBelow(); //remove from current mid-list position
}
aElement->RemoveAfter(refFromElementBelow);
}
TInt COpenWfcWrapper::SetUiSurface(const TSurfaceId& aNewUiSurface)
{
TInt err = RegisterSurface(aNewUiSurface);
if (!err)
{
if(iUiElement1)
{
err = iUiElement1->ConnectSurface(aNewUiSurface);
STD_ASSERT_DEBUG(!err, EPluginPanicNewUiSurfaceUnsettable);
}
if(iUiElement2)
{
err = iUiElement2->ConnectSurface(aNewUiSurface);
STD_ASSERT_DEBUG(!err, EPluginPanicNewUiSurfaceUnsettable);
}
}
if(!err)
{
if(!iUiSurface.IsNull())
{
// This should not fail as the surface will no longer be used by any element
err = UnregisterSurface(iUiSurface);
if (err == KErrInUse) // This is not needed once openwf implementation is corrected:
// It should not return KErrInUse if it is only the backend holding onto it.
{
err = KErrNone;
}
STD_ASSERT_DEBUG(!err, EPluginPanicPreviousUiSurfaceUnregisterable);
}
iUiSurface = aNewUiSurface;
}
return err;
}
TInt COpenWfcWrapper::AddElement(MWsElement* aElement, MWsElement* aAbove)
{
TInt err = KErrNone;
CElementWrapper* addedElement = static_cast<CElementWrapper*>(aElement);
CElementWrapper* insertAboveThisElement = static_cast<CElementWrapper*>(aAbove);
if (aElement == aAbove)
{
return KErrArgument;
}
if (addedElement == NULL || &addedElement->Owner()!=this ||
(insertAboveThisElement && &insertAboveThisElement->Owner()!=this) ||
(addedElement->UpdateFlags() & CElementWrapper::EUpdate_Destroy))
{
return KErrArgument;
}
if (insertAboveThisElement &&
((!insertAboveThisElement->RefsMyElementBelow() && iSceneElementList != insertAboveThisElement) ||
(insertAboveThisElement->UpdateFlags() & (CElementWrapper::EUpdate_Remove | CElementWrapper::EUpdate_Destroy))))
{
return KErrArgument;
}
//the UI element is a special case since we set and maintain the surface
TUint32 renderStageFlags;
addedElement->GetRenderStageFlags(renderStageFlags);
if (renderStageFlags & MWsElement::EElementIsIndirectlyRenderedUserInterface ||
renderStageFlags & MWsElement::EElementIsDirectlyRenderedUserInterface)
{
err = AttachSurfaceToUiElement(addedElement);
}
if(!err)
{
//figure out which element to add the element above
const TSurfaceId& newSurf = addedElement->ConnectedSurface();
if (!addedElement->ConnectedSurface().IsNull())
{
//is surface registered
WFCSource newSource = IncEltRefRegSource(newSurf);
if (newSource == WFC_INVALID_HANDLE)
{ //suggests the surface was not registered
return KErrArgument;
}
DecEltRefRegSource(newSurf); //only need to decrement if it found a source
}
RemoveElementFromSceneList(addedElement);
// figure out which element to add it below
CElementWrapper** insertBelowThisElement = NULL;
if (insertAboveThisElement)
{
insertBelowThisElement=&insertAboveThisElement->MyElementAbove();
}
else
{
insertBelowThisElement=&iSceneElementList;
}
addedElement->InsertAfter(*insertBelowThisElement,insertAboveThisElement,CElementWrapper::EUpdate_Insert);
SetCompositionModified();
}
return err;
}
void COpenWfcWrapper::Compose(const TSurfaceId& aOffScreenTarget, TRequestStatus* aCompleted)
{
if (aOffScreenTarget.IsNull())
{
if (aCompleted)
{
User::RequestComplete(aCompleted, KErrNone);
return;
}
}
ComposeInternal(aOffScreenTarget,TPoint(0,0),iSceneElementList,NULL,aCompleted);
}
void COpenWfcWrapper::Compose(const TSurfaceId& aOffScreenTarget, const TPoint& aOrigin,
MWsElement* aStart, MWsElement* aEnd, TRequestStatus* aCompleted)
{
if (aOffScreenTarget.IsNull())
{
if (aCompleted)
{
User::RequestComplete(aCompleted, KErrNone);
return;
}
}
CElementWrapper* startElement=static_cast<CElementWrapper*>(aStart);
CElementWrapper* endElement=static_cast<CElementWrapper*>(aEnd);
if (startElement)
{
if ( &startElement->Owner()!=this
|| (startElement!=iSceneElementList && !startElement->ElementBelow())
|| (startElement->UpdateFlags() & (startElement->EUpdate_Remove|startElement->EUpdate_Destroy))
)
{
if (aCompleted)
{
RThread().RequestComplete(aCompleted, KErrArgument);
}
return;
}
if (endElement)
{ //If endElement is NULL then draw to end else draw including the specified endElement
TBool fail=EFalse;
if ( &endElement->Owner()!=this
|| (endElement->UpdateFlags() & (endElement->EUpdate_Remove|endElement->EUpdate_Destroy))
)
{
fail=ETrue;
}
else
{
for (CElementWrapper* sceneElement=startElement;sceneElement!=endElement;sceneElement=sceneElement->MyElementAbove())
{
if (sceneElement==NULL)
{
fail=ETrue;
break;
}
}
}
if (fail)
{
if (aCompleted)
{
RThread().RequestComplete(aCompleted, KErrArgument);
}
return;
}
aEnd=aEnd->ElementAbove(); //now scene does NOT include endElement. May now be NULL!
}
}
else
{
aEnd=NULL;
}
ComposeInternal(aOffScreenTarget,aOrigin,aStart,aEnd,aCompleted);
}
/** Internal compose does not check some errors.
* They should have already been checked by the public API caller.
* NOTE element aEnd is NOT composed by this internal method!
* Any elements pending removal will not be displayed (including aStart and aEnd.
*
* @param aOffScreenTarget A valid surface for offscreen composition.
* @param aOrigin The origin sets where the top-left corner of the
* surface is within the element coordinate system.
* @param aStart The starting element of the elements to be composed.
* @param aEnd The element above the last element to be composed (or NULL).
* @param aCompleted NULL or request status that will be set to KErrNone when
* the composition finishes.
**/
void COpenWfcWrapper::ComposeInternal (const TSurfaceId& aOffScreenTarget,
const TPoint& aOrigin,
MWsElement* aStart,
MWsElement* aEnd,
TRequestStatus* aCompleted)
{
// Initial approach reuses the device but it may be more safer to create, and destroy, its own device
CElementWrapper* startElement=static_cast<CElementWrapper*>(aStart);
CElementWrapper* endElement=static_cast<CElementWrapper*>(aEnd);
TInt err = KErrNone;
#ifdef _DEBUG
// clean previous errors
wfcGetError(iDevice);
#endif
if (aCompleted)
{
*aCompleted = KRequestPending;
}
OffScreenComposeGuard composeGuard(aCompleted);
WFCNativeStreamType stream=reinterpret_cast<WFCNativeStreamType>(&aOffScreenTarget);
RSurfaceManager::TInfoBuf buff;
err=SurfaceManager().SurfaceInfo(aOffScreenTarget,buff);
OPENWFC_ASSERT_DEBUG(err==KErrNone,TOpenWfcPanic(__LINE__));
if (err!=KErrNone || buff().iSize.iWidth ==0 || buff().iSize.iHeight == 0)
{
composeGuard.LogRequestStatusError(KErrArgument);
composeGuard.Close();
return;
}
// Create the native stream target
TSurfaceId targetSurfaceId = TSurfaceId::CreateNullId();
WFCNativeStreamType targetStream = WFC_INVALID_HANDLE;
OPENWFC_ASSERT_DEBUG(wfcGetError(iDevice)==WFC_ERROR_NONE,(TOpenWfcPanic)__LINE__);
targetSurfaceId = aOffScreenTarget;
targetStream = stream;
EGLint attrib_list[1] = {EGL_NONE };
EGLSyncKHR sync = eglCreateSyncKHR(iEGLDisplay,
EGL_SYNC_REUSABLE_KHR,
attrib_list);
if (sync == EGL_NO_SYNC_KHR)
{
composeGuard.LogRequestStatusError(KErrNoMemory);
composeGuard.Close();
return;
}
composeGuard.SetSync(sync, iEGLDisplay);
// Now, that we have the target surface stream we can create the temporary context
WFCContext offScreenContext = wfcCreateOffScreenContext(iDevice, targetStream, NULL);
if (offScreenContext == WFC_INVALID_HANDLE)
{
composeGuard.LogRequestStatusError(TranslateOpenWfcError(wfcGetError(iDevice)));
composeGuard.Close();
return;
}
composeGuard.SetDeviceAndContext(iDevice, offScreenContext);
TInt contextBackGroundColour = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_BG_COLOR);
wfcSetContextAttribi(iDevice, offScreenContext, WFC_CONTEXT_BG_COLOR, contextBackGroundColour);
OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
TPoint elementOffset(-aOrigin.iX,-aOrigin.iY);
// let's replicate the scene to the offscreen context
WFCElement previousTargetElement = WFC_INVALID_HANDLE;
for (CElementWrapper* elementScene = startElement; elementScene !=endElement; elementScene = elementScene->MyElementAbove())
{
if (!(elementScene->UpdateFlags()&(elementScene->EUpdate_Destroy|elementScene->EUpdate_Remove)))
{
// we do our best to replicate the elements
TInt err=elementScene->ReplicateElements(offScreenContext, previousTargetElement,elementOffset);
if (err)
{
composeGuard.LogRequestStatusError(err);
composeGuard.Close();
return;
}
}
}
// let's compose
wfcCommit(iDevice, offScreenContext, WFC_TRUE);
wfcCompose(iDevice, offScreenContext, WFC_TRUE);
wfcFence(iDevice, offScreenContext, iEGLDisplay, sync);
EGLTimeKHR timeout = (EGLTimeKHR) EGL_FOREVER_KHR;
OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
eglClientWaitSyncKHR(iEGLDisplay, sync, 0, timeout);
composeGuard.Close();
}
void COpenWfcWrapper::PauseComposition (void)
{
OPENWFC_ASSERT_DEBUG(iJobManager, EPanicWfcThreadManagerNotInitialised);
iAutonomousCompositionInitiated = ETrue;
iJobManager->CompositionPauseRequest();
}
void COpenWfcWrapper::ResumeComposition (void)
{
OPENWFC_ASSERT_DEBUG(iJobManager, EPanicWfcThreadManagerNotInitialised);
iAutonomousCompositionInitiated = ETrue;
iJobManager->CompositionResumeRequest();
}
TBitFlags32 COpenWfcWrapper::SupportedScreenRotations() const
{
TBitFlags32 result;
// we DO support, by default, all these rotations
result.Set(MWsScene::ESceneAntiClockwise0);
result.Set(MWsScene::ESceneAntiClockwise90);
result.Set(MWsScene::ESceneAntiClockwise180);
result.Set(MWsScene::ESceneAntiClockwise270);
return result;
}
void COpenWfcWrapper::SetScreenRotation(MWsScene::TSceneRotation aRotation)
{
#ifdef _DEBUG
// clean previous errors
(void)wfcGetError(iDevice);
#endif
if (aRotation != iRotation)
{
WFCRotation wfcRotation = WFC_ROTATION_0;
switch (aRotation)
{
case MWsScene::ESceneAntiClockwise90:
wfcRotation = WFC_ROTATION_90;
break;
case MWsScene::ESceneAntiClockwise180:
wfcRotation = WFC_ROTATION_180;
break;
case MWsScene::ESceneAntiClockwise270:
wfcRotation = WFC_ROTATION_270;
break;
default:
wfcRotation = WFC_ROTATION_0;
break;
}
iRotation = aRotation;
wfcSetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION, wfcRotation);
OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
}
SetCompositionModified();
}
TInt COpenWfcWrapper::SetConfiguration(const TDisplayConfiguration& aConfig)
{
return iContextDisplayControl->SetConfiguration (aConfig);
}
MWsScene::TSceneRotation COpenWfcWrapper::ScreenRotation() const
{
#ifdef _DEBUG
// clean previous errors
(void)wfcGetError(iDevice);
#endif
WFCint result = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION);
OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
MWsScene::TSceneRotation rotation = MWsScene::ESceneAntiClockwise0;
switch (result)
{
case WFC_ROTATION_90:
rotation = MWsScene::ESceneAntiClockwise90;
break;
case WFC_ROTATION_180:
rotation = MWsScene::ESceneAntiClockwise180;
break;
case WFC_ROTATION_270:
rotation = MWsScene::ESceneAntiClockwise270;
break;
case WFC_ROTATION_0:
default:
OPENWFC_ASSERT_DEBUG(result==WFC_ROTATION_0,(TOpenWfcPanic)__LINE__);
rotation = MWsScene::ESceneAntiClockwise0;
break;
}
return rotation;
}
TInt COpenWfcWrapper::NumberOfResolutions()const
{
if (iContextDisplayControl)
{
return iContextDisplayControl->NumberOfResolutions();
}
return KErrNotSupported;
}
TInt COpenWfcWrapper::GetResolutions(RArray<TResolution>& aResolutions)const
{
if (iContextDisplayControl)
{
return iContextDisplayControl->GetResolutions(aResolutions);
}
return KErrNotSupported;
}
void COpenWfcWrapper::GetConfiguration(TDisplayConfiguration& aConfig)const
{
if (iContextDisplayControl)
{
iContextDisplayControl->GetConfiguration (aConfig);
}
}
TInt COpenWfcWrapper::PreferredDisplayVersion() const
{
if (iContextDisplayControl)
{
return iContextDisplayControl->PreferredDisplayVersion();
}
return KErrNotSupported;
}
void COpenWfcWrapper::NotifyOnDisplayChange(TRequestStatus& aStatus)
{
// Stub for future implementation.
TRequestStatus *status = &aStatus;
RThread().RequestComplete(status, KErrNotSupported);
}
void COpenWfcWrapper::NotifyOnDisplayChangeCancel()
{
// Stub for future implementation.
}
void COpenWfcWrapper::NotifyOnConfigChange(TRequestStatus& aStatus)
{
// Stub for future implementation.
TRequestStatus *status = &aStatus;
RThread().RequestComplete(status, KErrNotSupported);
}
void COpenWfcWrapper::NotifyOnConfigChangeCancel()
{
// Stub for future implementation.
}
void COpenWfcWrapper::FlushSceneElementChanges()
{
while (CElementWrapper* curr = iRemoveElementList)
{
curr->FlushSceneChanges();
RemoveElementFromSceneList(curr);
if (curr->UpdateFlags() & CElementWrapper::EUpdate_Destroy)
{
delete curr;
}
}
iRemoveElementList=NULL;
if (CElementWrapper* curr=iSceneElementList)
{
for (CElementWrapper*next=curr->MyElementAbove(); curr; curr=next,next=curr?curr->MyElementAbove():NULL)
{
curr->FlushSceneChanges();
}
}
}
TInt COpenWfcWrapper::TranslateOpenWfcError(WFCErrorCode error)
{
switch (error)
{
case WFC_ERROR_NONE:
return KErrNone;
case WFC_ERROR_OUT_OF_MEMORY:
return KErrNoMemory;
case WFC_ERROR_ILLEGAL_ARGUMENT:
return KErrArgument;
case WFC_ERROR_BAD_ATTRIBUTE:
return KErrArgument;
case WFC_ERROR_BAD_DEVICE:
return KErrArgument;
case WFC_ERROR_UNSUPPORTED:
return KErrNotSupported;
case WFC_ERROR_IN_USE:
return KErrInUse;
case WFC_ERROR_BUSY:
return KErrServerBusy;
case WFC_ERROR_BAD_HANDLE:
return KErrBadHandle;
case WFC_ERROR_INCONSISTENCY:
return KErrGeneral;
case WFC_ERROR_FORCE_32BIT:
// intentional fall through
default:
return KErrUnknown;
}
}
void COpenWfcWrapper::DestroyAllContextElements(WFCDevice dev, WFCContext ctx)
{
// we try our best to destroy all elements of the specified context
if (dev != WFC_INVALID_HANDLE && ctx != WFC_INVALID_HANDLE)
{
WFCElement element = wfcGetContextAttribi(dev, ctx, WFC_CONTEXT_LOWEST_ELEMENT);
if (element != WFC_INVALID_HANDLE)
{
wfcDestroyElement(dev, element);
}
}
}
void COpenWfcWrapper::PauseCompositorIfNeeded()
{
if (!iPaused && iAllowCompositorPause && iWithinBeginEnd)
{
PauseComposition();
iPaused = ETrue;
}
}
/**
Sets the system state for modified scene composition.
- Pause OpenWF composition if the standard render stage is within a begin/end block.
- If not within a pause/end block then set a flag to indicate that the scene composition
has been modified. On entering the begin/end block composition will be paused appropriatly.
*/
void COpenWfcWrapper::SetCompositionModified()
{
PauseCompositorIfNeeded();
iCompositionModified = ETrue;
}
void COpenWfcWrapper::ResumeCompositorIfPaused()
{
if (iPaused)
ResumeComposition();
iPaused = EFalse;
}
void COpenWfcWrapper::Begin(const TRegion* aRegion)
{
iWithinBeginEnd = ETrue;
iAllowCompositorPause = (aRegion && !aRegion->IsEmpty());
if (iCompositionModified)
PauseCompositorIfNeeded();
}
TBool COpenWfcWrapper::CompositionDue()
{
return (iWithinBeginEnd && iCompositionModified);
}
void COpenWfcWrapper::End()
{
iWithinBeginEnd = EFalse;
}
TInt COpenWfcWrapper::FlushedSetConfiguration(const TDisplayConfiguration& /*aConfig*/)
{
OPENWFC_ASSERT_DEBUG(0, EPanicMethodNotImplemented);
TInt retval=KErrNone;
if (retval<=KErrNone)
{
SetCompositionModified();
}
return retval;
}
CDisplayPolicy* COpenWfcWrapper::DisplayPolicy()
{
return iDisplayPolicy;
}
TInt COpenWfcWrapper::AttachSurfaceToUiElement(CElementWrapper* aNewUiElement)
{
STD_ASSERT_DEBUG(!iUiSurface.IsNull(), EPluginPanicUiSurfaceIsNull);
if(iUiElement1 == NULL || iUiElement1 == aNewUiElement)
iUiElement1 = aNewUiElement;
else if(iUiElement2 == NULL || iUiElement2 == aNewUiElement)
iUiElement2 = aNewUiElement;
else
STD_ASSERT_DEBUG(EFalse, EPluginPanicDuplicateUiElement);
return aNewUiElement->ConnectSurface(iUiSurface);
}