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 mEventThreadSemaphore(),
91 mUpdateRenderThreadWaitCondition(),
92 mAdaptorInterfaces( adaptorInterfaces ),
93 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
94 mCore( adaptorInterfaces.GetCore() ),
95 mEnvironmentOptions( environmentOptions ),
96 mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
97 mSleepTrigger( NULL ),
98 mPreRenderCallback( 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 mPreRenderCallback;
141 delete mSleepTrigger;
144 void CombinedUpdateRenderController::Initialize()
148 // Ensure Update/Render Thread not already created
149 DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
151 // Create Update/Render Thread
152 mUpdateRenderThread = new pthread_t();
153 int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
154 DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
156 // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
157 // When this function returns, the application initialisation on the event thread should occur
160 void CombinedUpdateRenderController::Start()
164 DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
166 // Wait until all threads created in Initialise are up and running
167 for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
169 sem_wait( &mEventThreadSemaphore );
172 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
175 currentSurface->StartRender();
180 LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
182 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
184 DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Start\n" );
187 void CombinedUpdateRenderController::Pause()
193 PauseUpdateRenderThread();
195 AddPerformanceMarker( PerformanceInterface::PAUSED );
197 DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Pause\n" );
200 void CombinedUpdateRenderController::Resume()
204 if( !mRunning && IsUpdateRenderThreadPaused() )
206 LOG_EVENT( "Resuming" );
208 RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
210 AddPerformanceMarker( PerformanceInterface::RESUME );
216 DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume\n" );
219 void CombinedUpdateRenderController::Stop()
223 // Stop Rendering and the Update/Render Thread
224 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
227 currentSurface->StopRender();
230 StopUpdateRenderThread();
232 if( mUpdateRenderThread )
234 LOG_EVENT( "Destroying UpdateRenderThread" );
236 // wait for the thread to finish
237 pthread_join( *mUpdateRenderThread, NULL );
239 delete mUpdateRenderThread;
240 mUpdateRenderThread = NULL;
245 DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Stop\n" );
248 void CombinedUpdateRenderController::RequestUpdate()
252 // Increment the update-request count to the maximum
253 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
255 ++mUpdateRequestCount;
258 if( mRunning && IsUpdateRenderThreadPaused() )
260 LOG_EVENT( "Processing" );
262 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
265 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
266 mPendingRequestUpdate = TRUE;
269 void CombinedUpdateRenderController::RequestUpdateOnce()
271 // Increment the update-request count to the maximum
272 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
274 ++mUpdateRequestCount;
277 if( IsUpdateRenderThreadPaused() )
281 // Run Update/Render once
282 RunUpdateRenderThread( ONCE, false /* No animation progression */ );
286 void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
290 // Set the ThreadSyncronizationInterface on the new surface
291 newSurface->SetThreadSynchronization( *this );
293 LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
295 // Start replacing the surface.
297 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
298 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
299 mNewSurface = newSurface;
300 mUpdateRenderThreadWaitCondition.Notify( lock );
303 // Wait until the surface has been replaced
304 sem_wait( &mEventThreadSemaphore );
306 LOG_EVENT( "Surface replaced, event-thread continuing" );
309 void CombinedUpdateRenderController::ResizeSurface()
313 LOG_EVENT( "Resize the surface" );
316 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
317 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
318 mSurfaceResized = TRUE;
319 mUpdateRenderThreadWaitCondition.Notify( lock );
323 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
325 // Not protected by lock, but written to rarely so not worth adding a lock when reading
326 mDefaultFrameDelta = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
327 mDefaultFrameDurationMilliseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
328 mDefaultFrameDurationNanoseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
329 mDefaultHalfFrameNanoseconds = mDefaultFrameDurationNanoseconds / 2u;
331 LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
334 void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
337 LOG_EVENT( "Set PreRender Callback" );
339 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
340 if( mPreRenderCallback )
342 delete mPreRenderCallback;
344 mPreRenderCallback = callback;
347 ///////////////////////////////////////////////////////////////////////////////////////////////////
349 ///////////////////////////////////////////////////////////////////////////////////////////////////
351 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
353 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
354 mUpdateRenderRunCount = numberOfCycles;
355 mUpdateRenderThreadCanSleep = FALSE;
356 mUseElapsedTimeAfterWait = useElapsedTime;
357 LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
358 mUpdateRenderThreadWaitCondition.Notify( lock );
361 void CombinedUpdateRenderController::PauseUpdateRenderThread()
363 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
364 mUpdateRenderRunCount = 0;
367 void CombinedUpdateRenderController::StopUpdateRenderThread()
369 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
370 mDestroyUpdateRenderThread = TRUE;
371 mUpdateRenderThreadWaitCondition.Notify( lock );
374 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
376 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
377 return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
378 mUpdateRenderThreadCanSleep; // Report paused if sleeping
381 void CombinedUpdateRenderController::ProcessSleepRequest()
385 // Decrement Update request count
386 if( mUpdateRequestCount > 0 )
388 --mUpdateRequestCount;
391 // Can sleep if our update-request count is 0
392 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
393 if( mUpdateRequestCount == 0 )
395 LOG_EVENT( "Going to sleep" );
397 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
398 mUpdateRenderThreadCanSleep = TRUE;
402 ///////////////////////////////////////////////////////////////////////////////////////////////////
403 // UPDATE/RENDER THREAD
404 ///////////////////////////////////////////////////////////////////////////////////////////////////
406 void CombinedUpdateRenderController::UpdateRenderThread()
408 SetThreadName("RenderThread\0");
410 // Install a function for logging
411 mEnvironmentOptions.InstallLogFunction();
413 // Install a function for tracing
414 mEnvironmentOptions.InstallTraceFunction();
416 LOG_UPDATE_RENDER( "THREAD CREATED" );
418 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
421 currentSurface->InitializeGraphics( mAdaptorInterfaces.GetGraphicsInterface(), mAdaptorInterfaces.GetDisplayConnectionInterface() );
424 // Tell core it has a context
425 mCore.ContextCreated();
427 NotifyThreadInitialised();
430 uint64_t lastFrameTime;
431 TimeService::GetNanoseconds( lastFrameTime );
433 LOG_UPDATE_RENDER( "THREAD INITIALISED" );
435 bool useElapsedTime = true;
436 bool updateRequired = true;
437 uint64_t timeToSleepUntil = 0;
438 int extraFramesDropped = 0;
440 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
441 const bool renderToFboEnabled = 0u != renderToFboInterval;
442 unsigned int frameCount = 0u;
444 while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
446 LOG_UPDATE_RENDER_TRACE;
448 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
449 AddPerformanceMarker( PerformanceInterface::VSYNC );
451 uint64_t currentFrameStartTime = 0;
452 TimeService::GetNanoseconds( currentFrameStartTime );
454 const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
456 // Optional FPS Tracking when continuously rendering
457 if( useElapsedTime && mFpsTracker.Enabled() )
459 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
460 mFpsTracker.Track( absoluteTimeSinceLastRender );
463 lastFrameTime = currentFrameStartTime; // Store frame start time
465 //////////////////////////////
467 //////////////////////////////
469 RenderSurface* newSurface = ShouldSurfaceBeReplaced();
470 if( DALI_UNLIKELY( newSurface ) )
472 LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
474 // This is designed for replacing pixmap surfaces, but should work for window as well
475 // we need to delete the surface and renderable (pixmap / window)
476 // Then create a new pixmap/window and new surface
477 // If the new surface has a different display connection, then the context will be lost
479 mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
480 newSurface->InitializeGraphics( mAdaptorInterfaces.GetGraphicsInterface(), mAdaptorInterfaces.GetDisplayConnectionInterface() );
481 newSurface->ReplaceGraphicsSurface();
485 const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
488 //////////////////////////////
490 //////////////////////////////
492 const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
493 const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
495 uint64_t noOfFramesSinceLastUpdate = 1;
496 float frameDelta = 0.0f;
499 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
500 noOfFramesSinceLastUpdate += extraFramesDropped;
502 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
504 LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
506 Integration::UpdateStatus updateStatus;
508 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
509 mCore.Update( frameDelta,
515 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
517 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
519 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
520 if( updateStatus.NeedsNotification() )
522 mNotificationTrigger.Trigger();
523 LOG_UPDATE_RENDER( "Notification Triggered" );
527 bool surfaceResized = false;
528 bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
529 if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
531 if( updateStatus.SurfaceRectChanged() )
533 LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
535 surfaceResized = true;
539 // Optional logging of update/render status
540 mUpdateStatusLogger.Log( keepUpdatingStatus );
542 //////////////////////////////
544 //////////////////////////////
546 mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
548 if( mPreRenderCallback != NULL )
550 bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
553 delete mPreRenderCallback;
554 mPreRenderCallback = NULL;
558 currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
561 currentSurface->PreRender( surfaceResized );
564 Integration::RenderStatus renderStatus;
566 AddPerformanceMarker( PerformanceInterface::RENDER_START );
567 mCore.Render( renderStatus, mForceClear );
568 AddPerformanceMarker( PerformanceInterface::RENDER_END );
572 if( renderStatus.NeedsPostRender() )
576 currentSurface->PostRender( isRenderingToFbo, ( mNewSurface != NULL ), surfaceResized );
580 // Trigger event thread to request Update/Render thread to sleep if update not required
581 if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
583 mSleepTrigger->Trigger();
584 updateRequired = false;
585 LOG_UPDATE_RENDER( "Sleep Triggered" );
589 updateRequired = true;
592 //////////////////////////////
594 //////////////////////////////
596 extraFramesDropped = 0;
598 if (timeToSleepUntil == 0)
600 // If this is the first frame after the thread is initialized or resumed, we
601 // use the actual time the current frame starts from to calculate the time to
602 // sleep until the next frame.
603 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
607 // Otherwise, always use the sleep-until time calculated in the last frame to
608 // calculate the time to sleep until the next frame. In this way, if there is
609 // any time gap between the current frame and the next frame, or if update or
610 // rendering in the current frame takes too much time so that the specified
611 // sleep-until time has already passed, it will try to keep the frames syncing
612 // by shortening the duration of the next frame.
613 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
615 // Check the current time at the end of the frame
616 uint64_t currentFrameEndTime = 0;
617 TimeService::GetNanoseconds( currentFrameEndTime );
618 while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
620 // We are more than one frame behind already, so just drop the next frames
621 // until the sleep-until time is later than the current time so that we can
623 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
624 extraFramesDropped++;
628 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
629 if( 0u == renderToFboInterval )
631 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
632 TimeService::SleepUntil( timeToSleepUntil );
636 // Inform core of context destruction & shutdown EGL
637 mCore.ContextDestroyed();
638 currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
641 currentSurface->DestroySurface();
642 currentSurface = nullptr;
645 LOG_UPDATE_RENDER( "THREAD DESTROYED" );
647 // Uninstall the logging function
648 mEnvironmentOptions.UnInstallLogFunction();
651 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
653 useElapsedTime = true;
655 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
656 while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
657 ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
658 ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
659 ! mNewSurface && // Ensure we don't wait if we need to replace the surface
660 ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
662 LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
663 LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
664 LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
665 LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
666 LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
668 // Reset the time when the thread is waiting, so the sleep-until time for
669 // the first frame after resuming should be based on the actual start time
670 // of the first frame.
671 timeToSleepUntil = 0;
673 mUpdateRenderThreadWaitCondition.Wait( updateLock );
675 if( ! mUseElapsedTimeAfterWait )
677 useElapsedTime = false;
681 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
682 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
683 LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
684 LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
685 LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
687 mUseElapsedTimeAfterWait = FALSE;
688 mUpdateRenderThreadCanSleep = FALSE;
689 mPendingRequestUpdate = FALSE;
691 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
692 // requested number of cycles
693 if( mUpdateRenderRunCount > 0 )
695 --mUpdateRenderRunCount;
698 // Keep the update-render thread alive if this thread is NOT to be destroyed
699 return ! mDestroyUpdateRenderThread;
702 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
704 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
706 RenderSurface* newSurface = mNewSurface;
712 void CombinedUpdateRenderController::SurfaceReplaced()
714 // Just increment the semaphore
715 sem_post( &mEventThreadSemaphore );
718 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
720 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
721 return mSurfaceResized;
724 void CombinedUpdateRenderController::SurfaceResized()
726 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
727 mSurfaceResized = FALSE;
730 ///////////////////////////////////////////////////////////////////////////////////////////////////
732 ///////////////////////////////////////////////////////////////////////////////////////////////////
734 void CombinedUpdateRenderController::NotifyThreadInitialised()
736 // Just increment the semaphore
737 sem_post( &mEventThreadSemaphore );
740 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
742 if( mPerformanceInterface )
744 mPerformanceInterface->AddMarker( type );
748 /////////////////////////////////////////////////////////////////////////////////////////////////
749 // POST RENDERING: EVENT THREAD
750 /////////////////////////////////////////////////////////////////////////////////////////////////
752 void CombinedUpdateRenderController::PostRenderComplete()
754 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
755 mPostRendering = FALSE;
756 mUpdateRenderThreadWaitCondition.Notify( lock );
759 ///////////////////////////////////////////////////////////////////////////////////////////////////
760 // POST RENDERING: RENDER THREAD
761 ///////////////////////////////////////////////////////////////////////////////////////////////////
763 void CombinedUpdateRenderController::PostRenderStarted()
765 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
766 mPostRendering = TRUE;
769 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
771 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
772 while( mPostRendering &&
773 ! mNewSurface && // We should NOT wait if we're replacing the surface
774 ! mSurfaceResized && // We should NOT wait if we're resizing the surface
775 ! mDestroyUpdateRenderThread )
777 mUpdateRenderThreadWaitCondition.Wait( lock );
781 } // namespace Adaptor
783 } // namespace Internal