os/graphics/graphicscomposition/surfaceupdate/tsrc/tcompositionbackend.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 /**
    17  @file
    18  @test
    19  @internalComponent - Internal Symbian test code 
    20 */
    21 
    22 #include <e32std.h>
    23 #include "tcompositionbackend.h"
    24 #include <graphics/suerror.h>
    25 
    26 const TInt KNotificationsAtTime = 10; //how many notifications could be processed at a time, varies from 1...
    27 
    28 CTContentUpdateReceiver::CTContentUpdateReceiver(TInt aScreen) :
    29 	iScreen(aScreen), iVisible(ETrue)
    30 	{
    31 	RThread thread;
    32 	iReceiverThreadId = thread.Id();
    33 	}
    34 
    35 CTContentUpdateReceiver::~CTContentUpdateReceiver()
    36 	{
    37 	if(iPeriodic)
    38 		iPeriodic->Cancel();
    39 	delete iPeriodic;
    40 	iLock.Close();
    41 	iPriorityLock.Close();
    42 	}
    43 
    44 void CTContentUpdateReceiver::ConstructL()
    45 	{
    46 	TCallBack callback(CallBack);
    47 	callback.iPtr = this;
    48 	User::LeaveIfError(iLock.CreateLocal());
    49 	User::LeaveIfError(iPriorityLock.CreateLocal(0));
    50     iPeriodic= CPeriodic::NewL(CPeriodic::EPriorityStandard);
    51     iPeriodic->Start(TTimeIntervalMicroSeconds32(0),TTimeIntervalMicroSeconds32(KCompositionInterval), callback);
    52 	}
    53 
    54 CTContentUpdateReceiver* CTContentUpdateReceiver::NewL(TInt aScreen)
    55 	{
    56 	CTContentUpdateReceiver* receiver = new (ELeave) CTContentUpdateReceiver(aScreen);
    57 	CleanupStack::PushL(receiver);
    58 	receiver->ConstructL();
    59 	CleanupStack::Pop();
    60 	return receiver;  
    61 	}
    62 
    63 TInt    CTContentUpdateReceiver::Extension_(TUint aExtensionId, TAny*& aRetIface, TAny* a1)
    64     {
    65     switch (aExtensionId)
    66         {
    67         case MCompositionSurfaceUpdate::ETypeId:
    68             aRetIface= static_cast<MCompositionSurfaceUpdate*>(this);
    69             return KErrNone;
    70 
    71         default:    ;
    72         }
    73     return CExtensionContainer::Extension_(aExtensionId,aRetIface,a1);
    74     }
    75 
    76 TInt CTContentUpdateReceiver::CallBack(TAny *aAny)
    77 	{
    78 	return (static_cast <CTContentUpdateReceiver*> (aAny))->CheckNewNotifications();
    79 	}
    80 
    81 void CTContentUpdateReceiver::Stop()
    82 	{
    83     iLock.Wait();
    84 	iStop = ETrue;
    85     iLock.Signal();
    86 	}
    87 
    88 EXPORT_C void CTContentUpdateReceiver::SetVisible(TBool aVisible)
    89     {
    90     iLock.Wait();
    91     iVisible = aVisible;
    92     iLock.Signal();
    93     }
    94 
    95 TInt CTContentUpdateReceiver::CheckNewNotifications()
    96 	{
    97 	iLock.Wait();
    98  	if(iStop && (iNumberElements <= 0))
    99 		{
   100 	    iLock.Signal();
   101 		CActiveScheduler::Stop();
   102 		return 0;//the return value is irrelevant for CPeriodic function
   103 		}
   104 	if(iSetInternalPriority)
   105 		{
   106 		TRAPD(res, DoSetInternalPriorityL());
   107 	    iLock.Signal();
   108 		__ASSERT_ALWAYS(res ==KErrNone, User::Panic(_L("CheckNewNotifications"), KErrGeneral));
   109 		return 0;//the return value is irrelevant for CPeriodic function
   110 		}	
   111 	TInt index = 0;	
   112 	RThread thread;
   113 	TInt res = thread.Open(iThreadId);
   114 	__ASSERT_ALWAYS(res ==KErrNone, User::Panic(_L("CheckNewNotifications"), KErrGeneral));
   115 
   116 		//we will check only one limited amount of requests at the time
   117 	for(TInt iteration = 0; (iNumberElements > index) && (iteration < KNotificationsAtTime); iteration++)
   118 		{
   119 		if(iArray[index].iType == EReqDisplayed)
   120 			{
   121 			*(iArray[index].iTimeStamp) = User::FastCounter();
   122 			if(iCompositionOrder)
   123 				{
   124 				iCompositionOrder->SetOrder(EOrderComposition);
   125 				}
   126 			}
   127 		else if(iArray[index].iType == EReqDisplayedXTimes)
   128 			{
   129 			iArray[index].iDisplayedXTimes--;
   130 			if(iArray[index].iDisplayedXTimes > 0)
   131 				{
   132 				index++;
   133 				continue;
   134 				}
   135 			}
   136 		TRequestStatus* status = iArray[index].iStatus;
   137 		res = iVisible ? KErrNone : KErrNotVisible;
   138 		Remove(index);
   139 		thread.RequestComplete(status, res);
   140 		}
   141 	thread.Close();	
   142     iLock.Signal();
   143 	return 0;//the return value is irrelevant for CPeriodic function
   144 	}
   145 
   146 void CTContentUpdateReceiver::DoSetInternalPriorityL()
   147 	{
   148 	RThread thread;
   149 	User::LeaveIfError(thread.Open(iReceiverThreadId));
   150 	thread.SetPriority(iInternalPriority);
   151 	thread.Close();
   152 	TInt compositionInterval = KCompositionInterval;
   153 	CPeriodic::TPriority priority = CPeriodic::EPriorityStandard;
   154 	if(iInternalPriority < EPriorityNormal)
   155 		{
   156 		priority = CPeriodic::EPriorityIdle;
   157 		compositionInterval = KCompositionIntervalLong;
   158 		}
   159 	else if (iInternalPriority > EPriorityNormal)
   160 		{
   161 		priority = CPeriodic::EPriorityHigh;
   162 		compositionInterval = KCompositionIntervalShort;
   163 		}
   164 
   165 	TCallBack callback(CallBack);
   166 	callback.iPtr = this;
   167 	iPeriodic->Cancel();
   168 	delete iPeriodic;
   169 	iPeriodic= CPeriodic::NewL(priority);
   170 	iPeriodic->Start(TTimeIntervalMicroSeconds32(compositionInterval),TTimeIntervalMicroSeconds32(compositionInterval), callback);
   171 	iSetInternalPriority = EFalse;
   172 	iPriorityLock.Signal();
   173 	}
   174 
   175 EXPORT_C TInt CTContentUpdateReceiver::SetInternalPriority(TThreadPriority aInternalPriority)
   176 	{
   177 	iLock.Wait();
   178 	iInternalPriority = aInternalPriority;
   179 	iSetInternalPriority = ETrue;
   180     iLock.Signal();
   181 	
   182     //wait for the priority changes takes place
   183     iPriorityLock.Wait();
   184 	return KErrNone;
   185 	}
   186 
   187 void CTContentUpdateReceiver::ContentUpdated(const TSurfaceId& aId, 
   188 				TInt aBuffer, 
   189 				const TRegion* aRegion, 
   190 				TRequestStatus* aStatusAvailable, 
   191 				TRequestStatus* aStatusDisplayed, TUint32* aTimeStamp, 
   192 				TRequestStatus* aStatusDisplayedXTimes, TInt* aDisplayedXTimes)
   193 	{
   194 	(TAny)&aId;
   195 	(TAny)aBuffer;
   196 	(TAny)aRegion;
   197 	
   198 	iLock.Wait();
   199 	if(iStop)
   200 		{
   201 		if(aStatusAvailable)
   202 			{
   203 			User::RequestComplete(aStatusAvailable, KErrDied);
   204 			}
   205 		if(aStatusDisplayed)
   206 			{
   207 			User::RequestComplete(aStatusDisplayed, KErrDied);
   208 			}
   209 		if(aStatusDisplayedXTimes)
   210 			{
   211 			User::RequestComplete(aStatusDisplayedXTimes, KErrDied);
   212 			}
   213 	    iLock.Signal();
   214 		return;
   215 		}
   216 	
   217 	RThread thread;
   218 	iThreadId = thread.Id();
   219 	
   220 	if(aStatusAvailable)
   221 		{
   222 		Add(aStatusAvailable, EReqAvailable);
   223 		}
   224 	if(aStatusDisplayed)
   225 		{
   226 		Add(aStatusDisplayed, EReqDisplayed, 0, aTimeStamp);
   227 		}
   228 	if(aStatusDisplayedXTimes)
   229 		{
   230 		Add(aStatusDisplayedXTimes, EReqDisplayedXTimes, *aDisplayedXTimes);
   231 		}
   232     iLock.Signal();
   233 	}
   234 
   235 /** 
   236    Add notification to the list. The function is called from the SUS thread.
   237    The client of this API must use a lock mechanizm to preserve data integrity.
   238 */
   239 TInt CTContentUpdateReceiver::Add(TRequestStatus *aStatus, RequestType aType, 
   240 			TInt aDisplayedXTimes, TUint32* aTimeStamp)
   241 	{
   242  	TInt index = iNumberElements;
   243 	TInt max = sizeof(iArray) / sizeof(iArray[0]) - 1;
   244 	if(index >= max)
   245 		return KErrOverflow;
   246 	
   247 	iArray[index].iStatus = aStatus;
   248 	iArray[index].iType = aType;
   249 	iArray[index].iDisplayedXTimes = aDisplayedXTimes;
   250 	iArray[index].iTimeStamp = aTimeStamp;
   251 	
   252 	iNumberElements++;
   253 	return KErrNone;
   254 	}
   255 
   256 /** 
   257    Remove notification from the list.
   258    The function is called from the backend thread. 
   259    The client of this API must use a lock mechanizm to preserve data integrity.
   260 */
   261 void CTContentUpdateReceiver::Remove(TInt aIndex) 
   262 	{
   263 	TInt max = sizeof(iArray) / sizeof(iArray[0]) - 1;
   264 	if((aIndex < 0) || (aIndex >= max))
   265 			return;
   266 	
   267 	iNumberElements--;
   268 	if(aIndex < iNumberElements)
   269 		{
   270 		Mem::Move(&iArray[aIndex], &iArray[aIndex + 1], (iNumberElements - aIndex) * sizeof(RequestObject));
   271 		iArray[iNumberElements].iType= EReqEmpty;
   272 		}
   273 	else
   274 		{
   275 		iArray[aIndex].iType = EReqEmpty;
   276 		}	
   277 	}
   278 	
   279 TInt CTContentUpdateReceiver::ThreadFunction(TAny* aAny)
   280 	{
   281 	  // get clean-up stack
   282 	CTrapCleanup* cleanup=CTrapCleanup::New();
   283 	RThread thread;
   284 	_LIT(KTestReceiver, "TestReceiver");
   285 	__ASSERT_ALWAYS(cleanup!=NULL, thread.Panic( KTestReceiver, KErrNoMemory));
   286 	
   287 	  // create an active scheduler and server
   288 	CActiveScheduler *pA = new CActiveScheduler;
   289 	__ASSERT_ALWAYS(pA != NULL, thread.Panic( KTestReceiver, KErrNoMemory));
   290 
   291 	  //Install the active scheduler
   292 	CActiveScheduler::Install(pA);
   293 
   294 	CTContentUpdateReceiver *pCB = NULL;
   295 	TInt screen = * (static_cast <TInt*> (aAny));
   296 	TRAPD(err, pCB = CTContentUpdateReceiver::NewL(screen));
   297 	__ASSERT_ALWAYS(err == KErrNone, thread.Panic( KTestReceiver, err));
   298 	
   299  	*(static_cast <CTContentUpdateReceiver**> (aAny)) = pCB;
   300     
   301       // Let everyone know that we are ready to
   302       // deal with requests.
   303 	RThread::Rendezvous(KErrNone);
   304 	  // And start fielding requests from client(s).
   305 	CActiveScheduler::Start();
   306 
   307      // Tidy up... 	
   308 	delete pCB;
   309 	delete pA;
   310 	delete cleanup; 
   311 	
   312 	return KErrNone;
   313 	}
   314 
   315 _LIT(KMaskBackend, "CompositionBackend_%d");
   316 const TUint KDefaultHeapSize=0x10000;
   317 
   318 EXPORT_C TInt StartTestUpdateReceiver(CTContentUpdateReceiver*& aReceiver, TInt aScreen)
   319 	{
   320 	RThread compositionThread;
   321 	TInt res = KErrGeneral;
   322 	TBuf<64> contentUpdateReceiverThreadName;
   323 	TBuf<64> contentUpdateReceiverThreadMask;
   324 	
   325 	// Guarantee uniqueness of thread name by using timestamp
   326 	TTime tm;
   327 	TBuf<32> timeStamp;
   328 	tm.UniversalTime();
   329 	TRAP(res, tm.FormatL(timeStamp, _L("_%H%T%S%C")));
   330 	if(res != KErrNone)
   331 		{
   332 		return res;
   333 		}
   334 
   335 	contentUpdateReceiverThreadName.Format(KMaskBackend, aScreen);
   336 	contentUpdateReceiverThreadName.Append(timeStamp);
   337 	contentUpdateReceiverThreadMask = contentUpdateReceiverThreadName;
   338 	contentUpdateReceiverThreadMask.Insert(0, _L("*"));
   339 	TFindThread findThread(contentUpdateReceiverThreadMask);
   340 	TFullName name;
   341 	  // Need to check that the thread exists.
   342 	if (findThread.Next(name)!=KErrNone)
   343 		{
   344 		aReceiver = reinterpret_cast <CTContentUpdateReceiver*> (aScreen);
   345 		
   346 		  // Create the thread for the server.
   347 		res = compositionThread.Create(contentUpdateReceiverThreadName,
   348 			CTContentUpdateReceiver::ThreadFunction,
   349 			KDefaultStackSize,
   350 			KDefaultHeapSize,
   351 			KDefaultHeapSize,
   352 			(TAny*) &aReceiver
   353 			);
   354 			
   355           // The thread has been created OK so get it started - however
   356           // we need to make sure that it has started before we continue.
   357 		if (res==KErrNone)
   358 			{
   359 			TRequestStatus rendezvousStatus;
   360 			compositionThread.SetPriority(EPriorityNormal);
   361 			compositionThread.Rendezvous(rendezvousStatus);
   362 			compositionThread.Resume();
   363 			User::WaitForRequest(rendezvousStatus);
   364 			res = rendezvousStatus.Int();
   365 			}
   366 		}
   367 		compositionThread.Close();
   368 		return res;
   369 	}
   370 
   371 EXPORT_C void CloseTestUpdateReceiver(CTContentUpdateReceiver* aReceiver)
   372 	{
   373 	if(!aReceiver)
   374 		return;
   375 
   376 	TBuf<64> contentUpdateReceiverThreadName;
   377 	contentUpdateReceiverThreadName.Format(KMaskBackend, aReceiver->Screen());
   378 	TBuf<64> contentUpdateReceiverThreadMask;
   379 	contentUpdateReceiverThreadMask = contentUpdateReceiverThreadName;
   380 	contentUpdateReceiverThreadMask.Insert(0, _L("*"));
   381 	contentUpdateReceiverThreadMask.Append('*');
   382 	TFindThread findThread(contentUpdateReceiverThreadMask);
   383 	TFullName name;
   384 	RThread thread;
   385 	if((findThread.Next(name)!=KErrNone) ||
   386 		(thread.Open(findThread) != KErrNone))
   387 		{
   388 		thread.Close();
   389 		return;
   390 		}
   391 	TRequestStatus status; 
   392 	thread.Logon(status);
   393 	if(aReceiver)
   394 		aReceiver->Stop();
   395 	User::WaitForRequest(status);
   396 	thread.Close();
   397 	}