2 * Copyright (c) 2018 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>
31 #include <dali/devel-api/adaptor-framework/thread-settings.h>
45 const unsigned int CREATED_THREAD_COUNT = 1u;
47 const int CONTINUOUS = -1;
50 const unsigned int TRUE = 1u;
51 const unsigned int FALSE = 0u;
53 const unsigned int MILLISECONDS_PER_SECOND( 1e+3 );
54 const float NANOSECONDS_TO_SECOND( 1e-9f );
55 const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
56 const unsigned int NANOSECONDS_PER_MILLISECOND( 1e+6 );
58 // The following values will get calculated at compile time
59 const float DEFAULT_FRAME_DURATION_IN_SECONDS( 1.0f / 60.0f );
60 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * MILLISECONDS_PER_SECOND );
61 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * NANOSECONDS_PER_SECOND );
64 * 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
65 * there is a danger that, on the event-thread we could have:
66 * 1) An update-request where we do nothing as Update/Render thread still running.
67 * 2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
69 * 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:
70 * 1) MAIN THREAD: Update Request: COUNTER = 1
71 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
72 * 3) MAIN THREAD: Update Request: COUNTER = 2
73 * 4) MAIN THREAD: Sleep Request: COUNTER = 1 -> We do not sleep just yet
75 * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
76 * 1) MAIN THREAD: Update Request: COUNTER = 1
77 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
78 * 3) MAIN THREAD: Sleep Request: COUNTER = 0 -> Go to sleep
80 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
81 } // unnamed namespace
83 ///////////////////////////////////////////////////////////////////////////////////////////////////
85 ///////////////////////////////////////////////////////////////////////////////////////////////////
87 CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
88 : mFpsTracker( environmentOptions ),
89 mUpdateStatusLogger( environmentOptions ),
90 mRenderHelper( adaptorInterfaces ),
91 mEventThreadSemaphore(),
92 mUpdateRenderThreadWaitCondition(),
93 mAdaptorInterfaces( adaptorInterfaces ),
94 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
95 mCore( adaptorInterfaces.GetCore() ),
96 mEnvironmentOptions( environmentOptions ),
97 mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
98 mSleepTrigger( NULL ),
99 mUpdateRenderThread( NULL ),
100 mDefaultFrameDelta( 0.0f ),
101 mDefaultFrameDurationMilliseconds( 0u ),
102 mDefaultFrameDurationNanoseconds( 0u ),
103 mDefaultHalfFrameNanoseconds( 0u ),
104 mUpdateRequestCount( 0u ),
106 mUpdateRenderRunCount( 0 ),
107 mDestroyUpdateRenderThread( FALSE ),
108 mUpdateRenderThreadCanSleep( FALSE ),
109 mPendingRequestUpdate( FALSE ),
110 mUseElapsedTimeAfterWait( FALSE ),
112 mPostRendering( FALSE ),
113 mSurfaceResized( FALSE ),
118 // Initialise frame delta/duration variables first
119 SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
121 // Set the thread-synchronization interface on the render-surface
122 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
125 currentSurface->SetThreadSynchronization( *this );
128 TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
129 mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
131 sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called
134 CombinedUpdateRenderController::~CombinedUpdateRenderController()
140 delete mSleepTrigger;
143 void CombinedUpdateRenderController::Initialize()
147 // Ensure Update/Render Thread not already created
148 DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
150 // Create Update/Render Thread
151 mUpdateRenderThread = new pthread_t();
152 int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
153 DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
155 // The Update/Render thread will now run and initialise EGL etc. and will then wait for Start to be called
156 // When this function returns, the application initialisation on the event thread should occur
159 void CombinedUpdateRenderController::Start()
163 DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
165 // Wait until all threads created in Initialise are up and running
166 for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
168 sem_wait( &mEventThreadSemaphore );
171 mRenderHelper.Start();
175 LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
177 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
180 void CombinedUpdateRenderController::Pause()
186 PauseUpdateRenderThread();
188 AddPerformanceMarker( PerformanceInterface::PAUSED );
191 void CombinedUpdateRenderController::Resume()
195 if( !mRunning && IsUpdateRenderThreadPaused() )
197 LOG_EVENT( "Resuming" );
199 RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
201 AddPerformanceMarker( PerformanceInterface::RESUME );
208 void CombinedUpdateRenderController::Stop()
212 // Stop Rendering and the Update/Render Thread
213 mRenderHelper.Stop();
215 StopUpdateRenderThread();
217 if( mUpdateRenderThread )
219 LOG_EVENT( "Destroying UpdateRenderThread" );
221 // wait for the thread to finish
222 pthread_join( *mUpdateRenderThread, NULL );
224 delete mUpdateRenderThread;
225 mUpdateRenderThread = NULL;
231 void CombinedUpdateRenderController::RequestUpdate()
235 // Increment the update-request count to the maximum
236 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
238 ++mUpdateRequestCount;
241 if( mRunning && IsUpdateRenderThreadPaused() )
243 LOG_EVENT( "Processing" );
245 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
248 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
249 mPendingRequestUpdate = TRUE;
252 void CombinedUpdateRenderController::RequestUpdateOnce()
254 // Increment the update-request count to the maximum
255 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
257 ++mUpdateRequestCount;
260 if( IsUpdateRenderThreadPaused() )
264 // Run Update/Render once
265 RunUpdateRenderThread( ONCE, false /* No animation progression */ );
269 void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
273 // Set the ThreadSyncronizationInterface on the new surface
274 newSurface->SetThreadSynchronization( *this );
276 LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
278 // Start replacing the surface.
280 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
281 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
282 mNewSurface = newSurface;
283 mUpdateRenderThreadWaitCondition.Notify( lock );
286 // Wait until the surface has been replaced
287 sem_wait( &mEventThreadSemaphore );
289 LOG_EVENT( "Surface replaced, event-thread continuing" );
292 void CombinedUpdateRenderController::ResizeSurface()
296 LOG_EVENT( "Resize the surface" );
299 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
300 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
301 mSurfaceResized = TRUE;
302 mUpdateRenderThreadWaitCondition.Notify( lock );
306 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
308 // Not protected by lock, but written to rarely so not worth adding a lock when reading
309 mDefaultFrameDelta = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
310 mDefaultFrameDurationMilliseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
311 mDefaultFrameDurationNanoseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
312 mDefaultHalfFrameNanoseconds = mDefaultFrameDurationNanoseconds / 2u;
314 LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
317 ///////////////////////////////////////////////////////////////////////////////////////////////////
319 ///////////////////////////////////////////////////////////////////////////////////////////////////
321 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
323 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
324 mUpdateRenderRunCount = numberOfCycles;
325 mUpdateRenderThreadCanSleep = FALSE;
326 mUseElapsedTimeAfterWait = useElapsedTime;
327 LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
328 mUpdateRenderThreadWaitCondition.Notify( lock );
331 void CombinedUpdateRenderController::PauseUpdateRenderThread()
333 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
334 mUpdateRenderRunCount = 0;
337 void CombinedUpdateRenderController::StopUpdateRenderThread()
339 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
340 mDestroyUpdateRenderThread = TRUE;
341 mUpdateRenderThreadWaitCondition.Notify( lock );
344 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
346 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
347 return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
348 mUpdateRenderThreadCanSleep; // Report paused if sleeping
351 void CombinedUpdateRenderController::ProcessSleepRequest()
355 // Decrement Update request count
356 if( mUpdateRequestCount > 0 )
358 --mUpdateRequestCount;
361 // Can sleep if our update-request count is 0
362 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
363 if( mUpdateRequestCount == 0 )
365 LOG_EVENT( "Going to sleep" );
367 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
368 mUpdateRenderThreadCanSleep = TRUE;
372 ///////////////////////////////////////////////////////////////////////////////////////////////////
373 // UPDATE/RENDER THREAD
374 ///////////////////////////////////////////////////////////////////////////////////////////////////
376 void CombinedUpdateRenderController::UpdateRenderThread()
378 SetThreadName("RenderThread\0");
380 // Install a function for logging
381 mEnvironmentOptions.InstallLogFunction();
383 // Install a function for tracing
384 mEnvironmentOptions.InstallTraceFunction();
386 LOG_UPDATE_RENDER( "THREAD CREATED" );
388 mRenderHelper.InitializeEgl();
390 // tell core it has a context
391 mCore.ContextCreated();
393 NotifyThreadInitialised();
396 uint64_t lastFrameTime;
397 TimeService::GetNanoseconds( lastFrameTime );
399 LOG_UPDATE_RENDER( "THREAD INITIALISED" );
401 bool useElapsedTime = true;
402 bool updateRequired = true;
403 uint64_t timeToSleepUntil = 0;
404 int extraFramesDropped = 0;
406 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
407 const bool renderToFboEnabled = 0u != renderToFboInterval;
408 unsigned int frameCount = 0u;
410 while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
412 LOG_UPDATE_RENDER_TRACE;
414 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
415 AddPerformanceMarker( PerformanceInterface::VSYNC );
417 uint64_t currentFrameStartTime = 0;
418 TimeService::GetNanoseconds( currentFrameStartTime );
420 const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
422 // Optional FPS Tracking when continuously rendering
423 if( useElapsedTime && mFpsTracker.Enabled() )
425 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
426 mFpsTracker.Track( absoluteTimeSinceLastRender );
429 lastFrameTime = currentFrameStartTime; // Store frame start time
431 //////////////////////////////
433 //////////////////////////////
435 RenderSurface* newSurface = ShouldSurfaceBeReplaced();
436 if( DALI_UNLIKELY( newSurface ) )
438 LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
439 mRenderHelper.ReplaceSurface( newSurface );
443 const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
446 //////////////////////////////
448 //////////////////////////////
450 const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
451 const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
453 uint64_t noOfFramesSinceLastUpdate = 1;
454 float frameDelta = 0.0f;
457 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
458 noOfFramesSinceLastUpdate += extraFramesDropped;
460 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
462 LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
464 Integration::UpdateStatus updateStatus;
466 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
467 mCore.Update( frameDelta,
473 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
475 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
477 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
478 if( updateStatus.NeedsNotification() )
480 mNotificationTrigger.Trigger();
481 LOG_UPDATE_RENDER( "Notification Triggered" );
485 bool surfaceResized = ShouldSurfaceBeResized();
486 if( DALI_UNLIKELY( surfaceResized ) )
488 // RenderHelper::ResizeSurface() should be called right after a viewport is changed.
489 if( updateStatus.SurfaceRectChanged() )
491 LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
492 mRenderHelper.ResizeSurface();
497 // Optional logging of update/render status
498 mUpdateStatusLogger.Log( keepUpdatingStatus );
500 //////////////////////////////
502 //////////////////////////////
504 mRenderHelper.ConsumeEvents();
505 mRenderHelper.PreRender();
507 Integration::RenderStatus renderStatus;
509 AddPerformanceMarker( PerformanceInterface::RENDER_START );
510 mCore.Render( renderStatus, mForceClear );
511 AddPerformanceMarker( PerformanceInterface::RENDER_END );
515 if( renderStatus.NeedsPostRender() )
517 mRenderHelper.PostRender( isRenderingToFbo );
520 // Trigger event thread to request Update/Render thread to sleep if update not required
521 if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
522 ! renderStatus.NeedsUpdate() )
524 mSleepTrigger->Trigger();
525 updateRequired = false;
526 LOG_UPDATE_RENDER( "Sleep Triggered" );
530 updateRequired = true;
533 //////////////////////////////
535 //////////////////////////////
537 extraFramesDropped = 0;
539 if (timeToSleepUntil == 0)
541 // If this is the first frame after the thread is initialized or resumed, we
542 // use the actual time the current frame starts from to calculate the time to
543 // sleep until the next frame.
544 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
548 // Otherwise, always use the sleep-until time calculated in the last frame to
549 // calculate the time to sleep until the next frame. In this way, if there is
550 // any time gap between the current frame and the next frame, or if update or
551 // rendering in the current frame takes too much time so that the specified
552 // sleep-until time has already passed, it will try to keep the frames syncing
553 // by shortening the duration of the next frame.
554 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
556 // Check the current time at the end of the frame
557 uint64_t currentFrameEndTime = 0;
558 TimeService::GetNanoseconds( currentFrameEndTime );
559 while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
561 // We are more than one frame behind already, so just drop the next frames
562 // until the sleep-until time is later than the current time so that we can
564 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
565 extraFramesDropped++;
569 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
570 if( 0u == renderToFboInterval )
572 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
573 TimeService::SleepUntil( timeToSleepUntil );
577 // Inform core of context destruction & shutdown EGL
578 mCore.ContextDestroyed();
579 mRenderHelper.ShutdownEgl();
581 LOG_UPDATE_RENDER( "THREAD DESTROYED" );
583 // Uninstall the logging function
584 mEnvironmentOptions.UnInstallLogFunction();
587 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
589 useElapsedTime = true;
591 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
592 while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
593 ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
594 ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
595 ! mNewSurface && // Ensure we don't wait if we need to replace the surface
596 ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
598 LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
599 LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
600 LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
601 LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
602 LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
604 // Reset the time when the thread is waiting, so the sleep-until time for
605 // the first frame after resuming should be based on the actual start time
606 // of the first frame.
607 timeToSleepUntil = 0;
609 mUpdateRenderThreadWaitCondition.Wait( updateLock );
611 if( ! mUseElapsedTimeAfterWait )
613 useElapsedTime = false;
617 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
618 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
619 LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
620 LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
621 LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
623 mUseElapsedTimeAfterWait = FALSE;
624 mUpdateRenderThreadCanSleep = FALSE;
625 mPendingRequestUpdate = FALSE;
627 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
628 // requested number of cycles
629 if( mUpdateRenderRunCount > 0 )
631 --mUpdateRenderRunCount;
634 // Keep the update-render thread alive if this thread is NOT to be destroyed
635 return ! mDestroyUpdateRenderThread;
638 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
640 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
642 RenderSurface* newSurface = mNewSurface;
648 void CombinedUpdateRenderController::SurfaceReplaced()
650 // Just increment the semaphore
651 sem_post( &mEventThreadSemaphore );
654 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
656 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
657 return mSurfaceResized;
660 void CombinedUpdateRenderController::SurfaceResized()
662 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
663 mSurfaceResized = FALSE;
666 ///////////////////////////////////////////////////////////////////////////////////////////////////
668 ///////////////////////////////////////////////////////////////////////////////////////////////////
670 void CombinedUpdateRenderController::NotifyThreadInitialised()
672 // Just increment the semaphore
673 sem_post( &mEventThreadSemaphore );
676 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
678 if( mPerformanceInterface )
680 mPerformanceInterface->AddMarker( type );
684 /////////////////////////////////////////////////////////////////////////////////////////////////
685 // POST RENDERING: EVENT THREAD
686 /////////////////////////////////////////////////////////////////////////////////////////////////
688 void CombinedUpdateRenderController::PostRenderComplete()
690 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
691 mPostRendering = FALSE;
692 mUpdateRenderThreadWaitCondition.Notify( lock );
695 ///////////////////////////////////////////////////////////////////////////////////////////////////
696 // POST RENDERING: RENDER THREAD
697 ///////////////////////////////////////////////////////////////////////////////////////////////////
699 void CombinedUpdateRenderController::PostRenderStarted()
701 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
702 mPostRendering = TRUE;
705 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
707 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
708 while( mPostRendering &&
709 ! mNewSurface && // We should NOT wait if we're replacing the surface
710 ! mSurfaceResized && // We should NOT wait if we're resizing the surface
711 ! mDestroyUpdateRenderThread )
713 mUpdateRenderThreadWaitCondition.Wait( lock );
717 } // namespace Adaptor
719 } // namespace Internal