2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/adaptor/common/combined-update-render-controller.h>
23 #include <dali/integration-api/platform-abstraction.h>
26 #include <dali/integration-api/trigger-event-factory.h>
27 #include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
28 #include <dali/internal/system/common/environment-options.h>
29 #include <dali/internal/system/common/time-service.h>
30 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
43 const unsigned int CREATED_THREAD_COUNT = 1u;
45 const int CONTINUOUS = -1;
48 const unsigned int TRUE = 1u;
49 const unsigned int FALSE = 0u;
51 const unsigned int MILLISECONDS_PER_SECOND( 1e+3 );
52 const float NANOSECONDS_TO_SECOND( 1e-9f );
53 const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
54 const unsigned int NANOSECONDS_PER_MILLISECOND( 1e+6 );
56 // The following values will get calculated at compile time
57 const float DEFAULT_FRAME_DURATION_IN_SECONDS( 1.0f / 60.0f );
58 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * MILLISECONDS_PER_SECOND );
59 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * NANOSECONDS_PER_SECOND );
62 * Handles the use case when an update-request is received JUST before we process a sleep-request. If we did not have an update-request count then
63 * there is a danger that, on the event-thread we could have:
64 * 1) An update-request where we do nothing as Update/Render thread still running.
65 * 2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
67 * Using a counter means we increment the counter on an update-request, and decrement it on a sleep-request. This handles the above scenario because:
68 * 1) MAIN THREAD: Update Request: COUNTER = 1
69 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
70 * 3) MAIN THREAD: Update Request: COUNTER = 2
71 * 4) MAIN THREAD: Sleep Request: COUNTER = 1 -> We do not sleep just yet
73 * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
74 * 1) MAIN THREAD: Update Request: COUNTER = 1
75 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
76 * 3) MAIN THREAD: Sleep Request: COUNTER = 0 -> Go to sleep
78 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
79 } // unnamed namespace
81 ///////////////////////////////////////////////////////////////////////////////////////////////////
83 ///////////////////////////////////////////////////////////////////////////////////////////////////
85 CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
86 : mFpsTracker( environmentOptions ),
87 mUpdateStatusLogger( environmentOptions ),
88 mRenderHelper( adaptorInterfaces ),
89 mEventThreadSemaphore(),
90 mUpdateRenderThreadWaitCondition(),
91 mAdaptorInterfaces( adaptorInterfaces ),
92 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
93 mCore( adaptorInterfaces.GetCore() ),
94 mEnvironmentOptions( environmentOptions ),
95 mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
96 mSleepTrigger( NULL ),
97 mUpdateRenderThread( NULL ),
98 mDefaultFrameDelta( 0.0f ),
99 mDefaultFrameDurationMilliseconds( 0u ),
100 mDefaultFrameDurationNanoseconds( 0u ),
101 mDefaultHalfFrameNanoseconds( 0u ),
102 mUpdateRequestCount( 0u ),
104 mUpdateRenderRunCount( 0 ),
105 mDestroyUpdateRenderThread( FALSE ),
106 mUpdateRenderThreadCanSleep( FALSE ),
107 mPendingRequestUpdate( FALSE ),
108 mUseElapsedTimeAfterWait( FALSE ),
110 mPostRendering( FALSE ),
111 mSurfaceResized( FALSE ),
116 // Initialise frame delta/duration variables first
117 SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
119 // Set the thread-synchronization interface on the render-surface
120 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
123 currentSurface->SetThreadSynchronization( *this );
126 TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
127 mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
129 sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called
132 CombinedUpdateRenderController::~CombinedUpdateRenderController()
138 delete mSleepTrigger;
141 void CombinedUpdateRenderController::Initialize()
145 // Ensure Update/Render Thread not already created
146 DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
148 // Create Update/Render Thread
149 mUpdateRenderThread = new pthread_t();
150 int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
151 DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
153 // The Update/Render thread will now run and initialise EGL etc. and will then wait for Start to be called
154 // When this function returns, the application initialisation on the event thread should occur
157 void CombinedUpdateRenderController::Start()
161 DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
163 // Wait until all threads created in Initialise are up and running
164 for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
166 sem_wait( &mEventThreadSemaphore );
169 mRenderHelper.Start();
173 LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
175 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
178 void CombinedUpdateRenderController::Pause()
184 PauseUpdateRenderThread();
186 AddPerformanceMarker( PerformanceInterface::PAUSED );
189 void CombinedUpdateRenderController::Resume()
193 if( !mRunning && IsUpdateRenderThreadPaused() )
195 LOG_EVENT( "Resuming" );
197 RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
199 AddPerformanceMarker( PerformanceInterface::RESUME );
206 void CombinedUpdateRenderController::Stop()
210 // Stop Rendering and the Update/Render Thread
211 mRenderHelper.Stop();
213 StopUpdateRenderThread();
215 if( mUpdateRenderThread )
217 LOG_EVENT( "Destroying UpdateRenderThread" );
219 // wait for the thread to finish
220 pthread_join( *mUpdateRenderThread, NULL );
222 delete mUpdateRenderThread;
223 mUpdateRenderThread = NULL;
229 void CombinedUpdateRenderController::RequestUpdate()
233 // Increment the update-request count to the maximum
234 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
236 ++mUpdateRequestCount;
239 if( mRunning && IsUpdateRenderThreadPaused() )
241 LOG_EVENT( "Processing" );
243 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
246 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
247 mPendingRequestUpdate = TRUE;
250 void CombinedUpdateRenderController::RequestUpdateOnce()
252 // Increment the update-request count to the maximum
253 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
255 ++mUpdateRequestCount;
258 if( IsUpdateRenderThreadPaused() )
262 // Run Update/Render once
263 RunUpdateRenderThread( ONCE, false /* No animation progression */ );
267 void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
271 // Set the ThreadSyncronizationInterface on the new surface
272 newSurface->SetThreadSynchronization( *this );
274 LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
276 // Start replacing the surface.
278 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
279 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
280 mNewSurface = newSurface;
281 mUpdateRenderThreadWaitCondition.Notify( lock );
284 // Wait until the surface has been replaced
285 sem_wait( &mEventThreadSemaphore );
287 LOG_EVENT( "Surface replaced, event-thread continuing" );
290 void CombinedUpdateRenderController::ResizeSurface()
294 LOG_EVENT( "Starting to resize the surface, event-thread blocked" );
296 // Start resizing the surface.
298 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
299 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
300 mSurfaceResized = TRUE;
301 mUpdateRenderThreadWaitCondition.Notify( lock );
304 // Wait until the surface has been resized
305 sem_wait( &mEventThreadSemaphore );
307 LOG_EVENT( "Surface resized, event-thread continuing" );
310 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
312 // Not protected by lock, but written to rarely so not worth adding a lock when reading
313 mDefaultFrameDelta = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
314 mDefaultFrameDurationMilliseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
315 mDefaultFrameDurationNanoseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
316 mDefaultHalfFrameNanoseconds = mDefaultFrameDurationNanoseconds / 2u;
318 LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
321 ///////////////////////////////////////////////////////////////////////////////////////////////////
323 ///////////////////////////////////////////////////////////////////////////////////////////////////
325 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
327 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
328 mUpdateRenderRunCount = numberOfCycles;
329 mUpdateRenderThreadCanSleep = FALSE;
330 mUseElapsedTimeAfterWait = useElapsedTime;
331 LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
332 mUpdateRenderThreadWaitCondition.Notify( lock );
335 void CombinedUpdateRenderController::PauseUpdateRenderThread()
337 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
338 mUpdateRenderRunCount = 0;
341 void CombinedUpdateRenderController::StopUpdateRenderThread()
343 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
344 mDestroyUpdateRenderThread = TRUE;
345 mUpdateRenderThreadWaitCondition.Notify( lock );
348 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
350 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
351 return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
352 mUpdateRenderThreadCanSleep; // Report paused if sleeping
355 void CombinedUpdateRenderController::ProcessSleepRequest()
359 // Decrement Update request count
360 if( mUpdateRequestCount > 0 )
362 --mUpdateRequestCount;
365 // Can sleep if our update-request count is 0
366 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
367 if( mUpdateRequestCount == 0 )
369 LOG_EVENT( "Going to sleep" );
371 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
372 mUpdateRenderThreadCanSleep = TRUE;
376 ///////////////////////////////////////////////////////////////////////////////////////////////////
377 // UPDATE/RENDER THREAD
378 ///////////////////////////////////////////////////////////////////////////////////////////////////
380 void CombinedUpdateRenderController::UpdateRenderThread()
382 // Install a function for logging
383 mEnvironmentOptions.InstallLogFunction();
385 LOG_UPDATE_RENDER( "THREAD CREATED" );
387 mRenderHelper.InitializeEgl();
389 // tell core it has a context
390 mCore.ContextCreated();
392 NotifyThreadInitialised();
395 uint64_t lastFrameTime;
396 TimeService::GetNanoseconds( lastFrameTime );
398 LOG_UPDATE_RENDER( "THREAD INITIALISED" );
400 bool useElapsedTime = true;
401 bool updateRequired = true;
402 uint64_t timeToSleepUntil = 0;
403 int extraFramesDropped = 0;
405 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
406 const bool renderToFboEnabled = 0u != renderToFboInterval;
407 unsigned int frameCount = 0u;
409 while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
411 LOG_UPDATE_RENDER_TRACE;
413 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
414 AddPerformanceMarker( PerformanceInterface::VSYNC );
416 uint64_t currentFrameStartTime = 0;
417 TimeService::GetNanoseconds( currentFrameStartTime );
419 const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
421 // Optional FPS Tracking when continuously rendering
422 if( useElapsedTime && mFpsTracker.Enabled() )
424 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
425 mFpsTracker.Track( absoluteTimeSinceLastRender );
428 lastFrameTime = currentFrameStartTime; // Store frame start time
430 //////////////////////////////
432 //////////////////////////////
434 RenderSurface* newSurface = ShouldSurfaceBeReplaced();
435 if( DALI_UNLIKELY( newSurface ) )
437 LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
438 mRenderHelper.ReplaceSurface( newSurface );
442 //////////////////////////////
444 //////////////////////////////
446 const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
449 // The resizing will be applied in the next loop
450 bool surfaceResized = ShouldSurfaceBeResized();
451 if( DALI_UNLIKELY( surfaceResized ) )
453 LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
454 mRenderHelper.ResizeSurface();
458 //////////////////////////////
460 //////////////////////////////
462 const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
463 const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
465 uint64_t noOfFramesSinceLastUpdate = 1;
466 float frameDelta = 0.0f;
469 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
470 noOfFramesSinceLastUpdate += extraFramesDropped;
472 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
474 LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
476 Integration::UpdateStatus updateStatus;
478 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
479 mCore.Update( frameDelta,
485 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
487 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
489 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
490 if( updateStatus.NeedsNotification() )
492 mNotificationTrigger.Trigger();
493 LOG_UPDATE_RENDER( "Notification Triggered" );
496 // Optional logging of update/render status
497 mUpdateStatusLogger.Log( keepUpdatingStatus );
499 //////////////////////////////
501 //////////////////////////////
503 mRenderHelper.ConsumeEvents();
504 mRenderHelper.PreRender();
506 Integration::RenderStatus renderStatus;
508 AddPerformanceMarker( PerformanceInterface::RENDER_START );
509 mCore.Render( renderStatus, mForceClear );
510 AddPerformanceMarker( PerformanceInterface::RENDER_END );
514 if( renderStatus.NeedsPostRender() )
516 mRenderHelper.PostRender( isRenderingToFbo );
519 // Trigger event thread to request Update/Render thread to sleep if update not required
520 if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
521 ! renderStatus.NeedsUpdate() )
523 mSleepTrigger->Trigger();
524 updateRequired = false;
525 LOG_UPDATE_RENDER( "Sleep Triggered" );
529 updateRequired = true;
532 //////////////////////////////
534 //////////////////////////////
536 extraFramesDropped = 0;
538 if (timeToSleepUntil == 0)
540 // If this is the first frame after the thread is initialized or resumed, we
541 // use the actual time the current frame starts from to calculate the time to
542 // sleep until the next frame.
543 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
547 // Otherwise, always use the sleep-until time calculated in the last frame to
548 // calculate the time to sleep until the next frame. In this way, if there is
549 // any time gap between the current frame and the next frame, or if update or
550 // rendering in the current frame takes too much time so that the specified
551 // sleep-until time has already passed, it will try to keep the frames syncing
552 // by shortening the duration of the next frame.
553 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
555 // Check the current time at the end of the frame
556 uint64_t currentFrameEndTime = 0;
557 TimeService::GetNanoseconds( currentFrameEndTime );
558 while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
560 // We are more than one frame behind already, so just drop the next frames
561 // until the sleep-until time is later than the current time so that we can
563 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
564 extraFramesDropped++;
568 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
569 if( 0u == renderToFboInterval )
571 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
572 TimeService::SleepUntil( timeToSleepUntil );
576 // Inform core of context destruction & shutdown EGL
577 mCore.ContextDestroyed();
578 mRenderHelper.ShutdownEgl();
580 LOG_UPDATE_RENDER( "THREAD DESTROYED" );
582 // Uninstall the logging function
583 mEnvironmentOptions.UnInstallLogFunction();
586 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
588 useElapsedTime = true;
590 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
591 while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
592 ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
593 ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
594 ! mNewSurface && // Ensure we don't wait if we need to replace the surface
595 ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
597 LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
598 LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
599 LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
600 LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
601 LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
603 // Reset the time when the thread is waiting, so the sleep-until time for
604 // the first frame after resuming should be based on the actual start time
605 // of the first frame.
606 timeToSleepUntil = 0;
608 mUpdateRenderThreadWaitCondition.Wait( updateLock );
610 if( ! mUseElapsedTimeAfterWait )
612 useElapsedTime = false;
616 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
617 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
618 LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
619 LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
620 LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
622 mUseElapsedTimeAfterWait = FALSE;
623 mUpdateRenderThreadCanSleep = FALSE;
624 mPendingRequestUpdate = FALSE;
626 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
627 // requested number of cycles
628 if( mUpdateRenderRunCount > 0 )
630 --mUpdateRenderRunCount;
633 // Keep the update-render thread alive if this thread is NOT to be destroyed
634 return ! mDestroyUpdateRenderThread;
637 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
639 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
641 RenderSurface* newSurface = mNewSurface;
647 void CombinedUpdateRenderController::SurfaceReplaced()
649 // Just increment the semaphore
650 sem_post( &mEventThreadSemaphore );
653 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
655 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
657 bool surfaceSized = mSurfaceResized;
658 mSurfaceResized = FALSE;
663 void CombinedUpdateRenderController::SurfaceResized()
665 // Just increment the semaphore
666 sem_post( &mEventThreadSemaphore );
669 ///////////////////////////////////////////////////////////////////////////////////////////////////
671 ///////////////////////////////////////////////////////////////////////////////////////////////////
673 void CombinedUpdateRenderController::NotifyThreadInitialised()
675 // Just increment the semaphore
676 sem_post( &mEventThreadSemaphore );
679 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
681 if( mPerformanceInterface )
683 mPerformanceInterface->AddMarker( type );
687 /////////////////////////////////////////////////////////////////////////////////////////////////
688 // POST RENDERING: EVENT THREAD
689 /////////////////////////////////////////////////////////////////////////////////////////////////
691 void CombinedUpdateRenderController::PostRenderComplete()
693 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
694 mPostRendering = FALSE;
695 mUpdateRenderThreadWaitCondition.Notify( lock );
698 ///////////////////////////////////////////////////////////////////////////////////////////////////
699 // POST RENDERING: RENDER THREAD
700 ///////////////////////////////////////////////////////////////////////////////////////////////////
702 void CombinedUpdateRenderController::PostRenderStarted()
704 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
705 mPostRendering = TRUE;
708 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
710 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
711 while( mPostRendering &&
712 ! mNewSurface && // We should NOT wait if we're replacing the surface
713 ! mSurfaceResized && // We should NOT wait if we're resizing the surface
714 ! mDestroyUpdateRenderThread )
716 mUpdateRenderThreadWaitCondition.Wait( lock );
720 } // namespace Adaptor
722 } // namespace Internal