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 */ );
185 void CombinedUpdateRenderController::Pause()
191 PauseUpdateRenderThread();
193 AddPerformanceMarker( PerformanceInterface::PAUSED );
196 void CombinedUpdateRenderController::Resume()
200 if( !mRunning && IsUpdateRenderThreadPaused() )
202 LOG_EVENT( "Resuming" );
204 RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
206 AddPerformanceMarker( PerformanceInterface::RESUME );
213 void CombinedUpdateRenderController::Stop()
217 // Stop Rendering and the Update/Render Thread
218 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
221 currentSurface->StopRender();
224 StopUpdateRenderThread();
226 if( mUpdateRenderThread )
228 LOG_EVENT( "Destroying UpdateRenderThread" );
230 // wait for the thread to finish
231 pthread_join( *mUpdateRenderThread, NULL );
233 delete mUpdateRenderThread;
234 mUpdateRenderThread = NULL;
240 void CombinedUpdateRenderController::RequestUpdate()
244 // Increment the update-request count to the maximum
245 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
247 ++mUpdateRequestCount;
250 if( mRunning && IsUpdateRenderThreadPaused() )
252 LOG_EVENT( "Processing" );
254 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
257 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
258 mPendingRequestUpdate = TRUE;
261 void CombinedUpdateRenderController::RequestUpdateOnce()
263 // Increment the update-request count to the maximum
264 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
266 ++mUpdateRequestCount;
269 if( IsUpdateRenderThreadPaused() )
273 // Run Update/Render once
274 RunUpdateRenderThread( ONCE, false /* No animation progression */ );
278 void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
282 // Set the ThreadSyncronizationInterface on the new surface
283 newSurface->SetThreadSynchronization( *this );
285 LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
287 // Start replacing the surface.
289 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
290 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
291 mNewSurface = newSurface;
292 mUpdateRenderThreadWaitCondition.Notify( lock );
295 // Wait until the surface has been replaced
296 sem_wait( &mEventThreadSemaphore );
298 LOG_EVENT( "Surface replaced, event-thread continuing" );
301 void CombinedUpdateRenderController::ResizeSurface()
305 LOG_EVENT( "Resize the surface" );
308 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
309 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
310 mSurfaceResized = TRUE;
311 mUpdateRenderThreadWaitCondition.Notify( lock );
315 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
317 // Not protected by lock, but written to rarely so not worth adding a lock when reading
318 mDefaultFrameDelta = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
319 mDefaultFrameDurationMilliseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
320 mDefaultFrameDurationNanoseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
321 mDefaultHalfFrameNanoseconds = mDefaultFrameDurationNanoseconds / 2u;
323 LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
326 void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
329 LOG_EVENT( "Set PreRender Callback" );
331 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
332 if( mPreRenderCallback )
334 delete mPreRenderCallback;
336 mPreRenderCallback = callback;
339 ///////////////////////////////////////////////////////////////////////////////////////////////////
341 ///////////////////////////////////////////////////////////////////////////////////////////////////
343 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
345 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
346 mUpdateRenderRunCount = numberOfCycles;
347 mUpdateRenderThreadCanSleep = FALSE;
348 mUseElapsedTimeAfterWait = useElapsedTime;
349 LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
350 mUpdateRenderThreadWaitCondition.Notify( lock );
353 void CombinedUpdateRenderController::PauseUpdateRenderThread()
355 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
356 mUpdateRenderRunCount = 0;
359 void CombinedUpdateRenderController::StopUpdateRenderThread()
361 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
362 mDestroyUpdateRenderThread = TRUE;
363 mUpdateRenderThreadWaitCondition.Notify( lock );
366 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
368 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
369 return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
370 mUpdateRenderThreadCanSleep; // Report paused if sleeping
373 void CombinedUpdateRenderController::ProcessSleepRequest()
377 // Decrement Update request count
378 if( mUpdateRequestCount > 0 )
380 --mUpdateRequestCount;
383 // Can sleep if our update-request count is 0
384 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
385 if( mUpdateRequestCount == 0 )
387 LOG_EVENT( "Going to sleep" );
389 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
390 mUpdateRenderThreadCanSleep = TRUE;
394 ///////////////////////////////////////////////////////////////////////////////////////////////////
395 // UPDATE/RENDER THREAD
396 ///////////////////////////////////////////////////////////////////////////////////////////////////
398 void CombinedUpdateRenderController::UpdateRenderThread()
400 SetThreadName("RenderThread\0");
402 // Install a function for logging
403 mEnvironmentOptions.InstallLogFunction();
405 // Install a function for tracing
406 mEnvironmentOptions.InstallTraceFunction();
408 LOG_UPDATE_RENDER( "THREAD CREATED" );
410 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
413 currentSurface->InitializeGraphics( mAdaptorInterfaces.GetGraphicsInterface(), mAdaptorInterfaces.GetDisplayConnectionInterface() );
416 // Tell core it has a context
417 mCore.ContextCreated();
419 NotifyThreadInitialised();
422 uint64_t lastFrameTime;
423 TimeService::GetNanoseconds( lastFrameTime );
425 LOG_UPDATE_RENDER( "THREAD INITIALISED" );
427 bool useElapsedTime = true;
428 bool updateRequired = true;
429 uint64_t timeToSleepUntil = 0;
430 int extraFramesDropped = 0;
432 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
433 const bool renderToFboEnabled = 0u != renderToFboInterval;
434 unsigned int frameCount = 0u;
436 while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
438 LOG_UPDATE_RENDER_TRACE;
440 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
441 AddPerformanceMarker( PerformanceInterface::VSYNC );
443 uint64_t currentFrameStartTime = 0;
444 TimeService::GetNanoseconds( currentFrameStartTime );
446 const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
448 // Optional FPS Tracking when continuously rendering
449 if( useElapsedTime && mFpsTracker.Enabled() )
451 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
452 mFpsTracker.Track( absoluteTimeSinceLastRender );
455 lastFrameTime = currentFrameStartTime; // Store frame start time
457 //////////////////////////////
459 //////////////////////////////
461 RenderSurface* newSurface = ShouldSurfaceBeReplaced();
462 if( DALI_UNLIKELY( newSurface ) )
464 LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
466 // This is designed for replacing pixmap surfaces, but should work for window as well
467 // we need to delete the surface and renderable (pixmap / window)
468 // Then create a new pixmap/window and new surface
469 // If the new surface has a different display connection, then the context will be lost
471 mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
472 newSurface->InitializeGraphics( mAdaptorInterfaces.GetGraphicsInterface(), mAdaptorInterfaces.GetDisplayConnectionInterface() );
473 newSurface->ReplaceGraphicsSurface();
477 const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
480 //////////////////////////////
482 //////////////////////////////
484 const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
485 const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
487 uint64_t noOfFramesSinceLastUpdate = 1;
488 float frameDelta = 0.0f;
491 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
492 noOfFramesSinceLastUpdate += extraFramesDropped;
494 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
496 LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
498 Integration::UpdateStatus updateStatus;
500 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
501 mCore.Update( frameDelta,
507 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
509 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
511 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
512 if( updateStatus.NeedsNotification() )
514 mNotificationTrigger.Trigger();
515 LOG_UPDATE_RENDER( "Notification Triggered" );
519 bool surfaceResized = false;
520 bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
521 if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
523 if( updateStatus.SurfaceRectChanged() )
525 LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
527 surfaceResized = true;
531 // Optional logging of update/render status
532 mUpdateStatusLogger.Log( keepUpdatingStatus );
534 //////////////////////////////
536 //////////////////////////////
538 mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
540 if( mPreRenderCallback != NULL )
542 bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
545 delete mPreRenderCallback;
546 mPreRenderCallback = NULL;
550 currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
553 currentSurface->PreRender( surfaceResized );
556 Integration::RenderStatus renderStatus;
558 AddPerformanceMarker( PerformanceInterface::RENDER_START );
559 mCore.Render( renderStatus, mForceClear );
560 AddPerformanceMarker( PerformanceInterface::RENDER_END );
564 if( renderStatus.NeedsPostRender() )
568 currentSurface->PostRender( isRenderingToFbo, ( mNewSurface != NULL ), surfaceResized );
572 // Trigger event thread to request Update/Render thread to sleep if update not required
573 if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
575 mSleepTrigger->Trigger();
576 updateRequired = false;
577 LOG_UPDATE_RENDER( "Sleep Triggered" );
581 updateRequired = true;
584 //////////////////////////////
586 //////////////////////////////
588 extraFramesDropped = 0;
590 if (timeToSleepUntil == 0)
592 // If this is the first frame after the thread is initialized or resumed, we
593 // use the actual time the current frame starts from to calculate the time to
594 // sleep until the next frame.
595 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
599 // Otherwise, always use the sleep-until time calculated in the last frame to
600 // calculate the time to sleep until the next frame. In this way, if there is
601 // any time gap between the current frame and the next frame, or if update or
602 // rendering in the current frame takes too much time so that the specified
603 // sleep-until time has already passed, it will try to keep the frames syncing
604 // by shortening the duration of the next frame.
605 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
607 // Check the current time at the end of the frame
608 uint64_t currentFrameEndTime = 0;
609 TimeService::GetNanoseconds( currentFrameEndTime );
610 while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
612 // We are more than one frame behind already, so just drop the next frames
613 // until the sleep-until time is later than the current time so that we can
615 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
616 extraFramesDropped++;
620 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
621 if( 0u == renderToFboInterval )
623 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
624 TimeService::SleepUntil( timeToSleepUntil );
628 // Inform core of context destruction & shutdown EGL
629 mCore.ContextDestroyed();
630 currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
633 currentSurface->DestroySurface();
634 currentSurface = nullptr;
637 LOG_UPDATE_RENDER( "THREAD DESTROYED" );
639 // Uninstall the logging function
640 mEnvironmentOptions.UnInstallLogFunction();
643 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
645 useElapsedTime = true;
647 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
648 while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
649 ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
650 ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
651 ! mNewSurface && // Ensure we don't wait if we need to replace the surface
652 ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
654 LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
655 LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
656 LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
657 LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
658 LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
660 // Reset the time when the thread is waiting, so the sleep-until time for
661 // the first frame after resuming should be based on the actual start time
662 // of the first frame.
663 timeToSleepUntil = 0;
665 mUpdateRenderThreadWaitCondition.Wait( updateLock );
667 if( ! mUseElapsedTimeAfterWait )
669 useElapsedTime = false;
673 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
674 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
675 LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
676 LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
677 LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
679 mUseElapsedTimeAfterWait = FALSE;
680 mUpdateRenderThreadCanSleep = FALSE;
681 mPendingRequestUpdate = FALSE;
683 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
684 // requested number of cycles
685 if( mUpdateRenderRunCount > 0 )
687 --mUpdateRenderRunCount;
690 // Keep the update-render thread alive if this thread is NOT to be destroyed
691 return ! mDestroyUpdateRenderThread;
694 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
696 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
698 RenderSurface* newSurface = mNewSurface;
704 void CombinedUpdateRenderController::SurfaceReplaced()
706 // Just increment the semaphore
707 sem_post( &mEventThreadSemaphore );
710 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
712 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
713 return mSurfaceResized;
716 void CombinedUpdateRenderController::SurfaceResized()
718 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
719 mSurfaceResized = FALSE;
722 ///////////////////////////////////////////////////////////////////////////////////////////////////
724 ///////////////////////////////////////////////////////////////////////////////////////////////////
726 void CombinedUpdateRenderController::NotifyThreadInitialised()
728 // Just increment the semaphore
729 sem_post( &mEventThreadSemaphore );
732 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
734 if( mPerformanceInterface )
736 mPerformanceInterface->AddMarker( type );
740 /////////////////////////////////////////////////////////////////////////////////////////////////
741 // POST RENDERING: EVENT THREAD
742 /////////////////////////////////////////////////////////////////////////////////////////////////
744 void CombinedUpdateRenderController::PostRenderComplete()
746 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
747 mPostRendering = FALSE;
748 mUpdateRenderThreadWaitCondition.Notify( lock );
751 ///////////////////////////////////////////////////////////////////////////////////////////////////
752 // POST RENDERING: RENDER THREAD
753 ///////////////////////////////////////////////////////////////////////////////////////////////////
755 void CombinedUpdateRenderController::PostRenderStarted()
757 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
758 mPostRendering = TRUE;
761 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
763 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
764 while( mPostRendering &&
765 ! mNewSurface && // We should NOT wait if we're replacing the surface
766 ! mSurfaceResized && // We should NOT wait if we're resizing the surface
767 ! mDestroyUpdateRenderThread )
769 mUpdateRenderThreadWaitCondition.Wait( lock );
773 } // namespace Adaptor
775 } // namespace Internal