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>
32 #include <dali/devel-api/adaptor-framework/thread-settings.h>
47 const unsigned int CREATED_THREAD_COUNT = 1u;
49 const int CONTINUOUS = -1;
52 const unsigned int TRUE = 1u;
53 const unsigned int FALSE = 0u;
55 const unsigned int MILLISECONDS_PER_SECOND( 1e+3 );
56 const float NANOSECONDS_TO_SECOND( 1e-9f );
57 const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
58 const unsigned int NANOSECONDS_PER_MILLISECOND( 1e+6 );
60 // The following values will get calculated at compile time
61 const float DEFAULT_FRAME_DURATION_IN_SECONDS( 1.0f / 60.0f );
62 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * MILLISECONDS_PER_SECOND );
63 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * NANOSECONDS_PER_SECOND );
66 * 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
67 * there is a danger that, on the event-thread we could have:
68 * 1) An update-request where we do nothing as Update/Render thread still running.
69 * 2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
71 * 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:
72 * 1) MAIN THREAD: Update Request: COUNTER = 1
73 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
74 * 3) MAIN THREAD: Update Request: COUNTER = 2
75 * 4) MAIN THREAD: Sleep Request: COUNTER = 1 -> We do not sleep just yet
77 * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
78 * 1) MAIN THREAD: Update Request: COUNTER = 1
79 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
80 * 3) MAIN THREAD: Sleep Request: COUNTER = 0 -> Go to sleep
82 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
83 } // unnamed namespace
85 ///////////////////////////////////////////////////////////////////////////////////////////////////
87 ///////////////////////////////////////////////////////////////////////////////////////////////////
89 CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
90 : mFpsTracker( environmentOptions ),
91 mUpdateStatusLogger( environmentOptions ),
92 mRenderHelper( adaptorInterfaces ),
93 mEventThreadSemaphore(),
94 mUpdateRenderThreadWaitCondition(),
95 mAdaptorInterfaces( adaptorInterfaces ),
96 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
97 mCore( adaptorInterfaces.GetCore() ),
98 mEnvironmentOptions( environmentOptions ),
99 mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
100 mSleepTrigger( NULL ),
101 mPreRenderCallback( NULL ),
102 mUpdateRenderThread( NULL ),
103 mDefaultFrameDelta( 0.0f ),
104 mDefaultFrameDurationMilliseconds( 0u ),
105 mDefaultFrameDurationNanoseconds( 0u ),
106 mDefaultHalfFrameNanoseconds( 0u ),
107 mUpdateRequestCount( 0u ),
109 mUpdateRenderRunCount( 0 ),
110 mDestroyUpdateRenderThread( FALSE ),
111 mUpdateRenderThreadCanSleep( FALSE ),
112 mPendingRequestUpdate( FALSE ),
113 mUseElapsedTimeAfterWait( FALSE ),
115 mPostRendering( FALSE ),
116 mSurfaceResized( FALSE ),
121 // Initialise frame delta/duration variables first
122 SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
124 // Set the thread-synchronization interface on the render-surface
125 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
128 currentSurface->SetThreadSynchronization( *this );
131 TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
132 mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
134 sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called
137 CombinedUpdateRenderController::~CombinedUpdateRenderController()
143 delete mPreRenderCallback;
144 delete mSleepTrigger;
147 void CombinedUpdateRenderController::Initialize()
151 // Ensure Update/Render Thread not already created
152 DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
154 // Create Update/Render Thread
155 mUpdateRenderThread = new pthread_t();
156 int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
157 DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
159 // The Update/Render thread will now run and initialise EGL etc. and will then wait for Start to be called
160 // When this function returns, the application initialisation on the event thread should occur
163 void CombinedUpdateRenderController::Start()
167 DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
169 // Wait until all threads created in Initialise are up and running
170 for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
172 sem_wait( &mEventThreadSemaphore );
175 mRenderHelper.Start();
179 LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
181 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
184 void CombinedUpdateRenderController::Pause()
190 PauseUpdateRenderThread();
192 AddPerformanceMarker( PerformanceInterface::PAUSED );
195 void CombinedUpdateRenderController::Resume()
199 if( !mRunning && IsUpdateRenderThreadPaused() )
201 LOG_EVENT( "Resuming" );
203 RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
205 AddPerformanceMarker( PerformanceInterface::RESUME );
212 void CombinedUpdateRenderController::Stop()
216 // Stop Rendering and the Update/Render Thread
217 mRenderHelper.Stop();
219 StopUpdateRenderThread();
221 if( mUpdateRenderThread )
223 LOG_EVENT( "Destroying UpdateRenderThread" );
225 // wait for the thread to finish
226 pthread_join( *mUpdateRenderThread, NULL );
228 delete mUpdateRenderThread;
229 mUpdateRenderThread = NULL;
235 void CombinedUpdateRenderController::RequestUpdate()
239 // Increment the update-request count to the maximum
240 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
242 ++mUpdateRequestCount;
245 if( mRunning && IsUpdateRenderThreadPaused() )
247 LOG_EVENT( "Processing" );
249 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
252 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
253 mPendingRequestUpdate = TRUE;
256 void CombinedUpdateRenderController::RequestUpdateOnce()
258 // Increment the update-request count to the maximum
259 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
261 ++mUpdateRequestCount;
264 if( IsUpdateRenderThreadPaused() )
268 // Run Update/Render once
269 RunUpdateRenderThread( ONCE, false /* No animation progression */ );
273 void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
277 // Set the ThreadSyncronizationInterface on the new surface
278 newSurface->SetThreadSynchronization( *this );
280 LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
282 // Start replacing the surface.
284 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
285 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
286 mNewSurface = newSurface;
287 mUpdateRenderThreadWaitCondition.Notify( lock );
290 // Wait until the surface has been replaced
291 sem_wait( &mEventThreadSemaphore );
293 LOG_EVENT( "Surface replaced, event-thread continuing" );
296 void CombinedUpdateRenderController::ResizeSurface()
300 LOG_EVENT( "Resize the surface" );
303 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
304 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
305 mSurfaceResized = TRUE;
306 mUpdateRenderThreadWaitCondition.Notify( lock );
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 void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
324 LOG_EVENT( "Set PreRender Callback" );
326 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
327 if( mPreRenderCallback )
329 delete mPreRenderCallback;
331 mPreRenderCallback = callback;
334 ///////////////////////////////////////////////////////////////////////////////////////////////////
336 ///////////////////////////////////////////////////////////////////////////////////////////////////
338 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
340 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
341 mUpdateRenderRunCount = numberOfCycles;
342 mUpdateRenderThreadCanSleep = FALSE;
343 mUseElapsedTimeAfterWait = useElapsedTime;
344 LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
345 mUpdateRenderThreadWaitCondition.Notify( lock );
348 void CombinedUpdateRenderController::PauseUpdateRenderThread()
350 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
351 mUpdateRenderRunCount = 0;
354 void CombinedUpdateRenderController::StopUpdateRenderThread()
356 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
357 mDestroyUpdateRenderThread = TRUE;
358 mUpdateRenderThreadWaitCondition.Notify( lock );
361 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
363 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
364 return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
365 mUpdateRenderThreadCanSleep; // Report paused if sleeping
368 void CombinedUpdateRenderController::ProcessSleepRequest()
372 // Decrement Update request count
373 if( mUpdateRequestCount > 0 )
375 --mUpdateRequestCount;
378 // Can sleep if our update-request count is 0
379 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
380 if( mUpdateRequestCount == 0 )
382 LOG_EVENT( "Going to sleep" );
384 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
385 mUpdateRenderThreadCanSleep = TRUE;
389 ///////////////////////////////////////////////////////////////////////////////////////////////////
390 // UPDATE/RENDER THREAD
391 ///////////////////////////////////////////////////////////////////////////////////////////////////
393 void CombinedUpdateRenderController::UpdateRenderThread()
395 #if defined(__GNUC__)
396 SetThreadName("RenderThread\0");
399 // Install a function for logging
400 mEnvironmentOptions.InstallLogFunction();
402 // Install a function for tracing
403 mEnvironmentOptions.InstallTraceFunction();
405 LOG_UPDATE_RENDER( "THREAD CREATED" );
407 mRenderHelper.InitializeEgl();
409 // tell core it has a context
410 mCore.ContextCreated();
412 NotifyThreadInitialised();
415 uint64_t lastFrameTime;
416 TimeService::GetNanoseconds( lastFrameTime );
418 LOG_UPDATE_RENDER( "THREAD INITIALISED" );
420 bool useElapsedTime = true;
421 bool updateRequired = true;
422 uint64_t timeToSleepUntil = 0;
423 int extraFramesDropped = 0;
425 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
426 const bool renderToFboEnabled = 0u != renderToFboInterval;
427 unsigned int frameCount = 0u;
429 while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
431 LOG_UPDATE_RENDER_TRACE;
433 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
434 AddPerformanceMarker( PerformanceInterface::VSYNC );
436 uint64_t currentFrameStartTime = 0;
437 TimeService::GetNanoseconds( currentFrameStartTime );
439 const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
441 // Optional FPS Tracking when continuously rendering
442 if( useElapsedTime && mFpsTracker.Enabled() )
444 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
445 mFpsTracker.Track( absoluteTimeSinceLastRender );
448 lastFrameTime = currentFrameStartTime; // Store frame start time
450 //////////////////////////////
452 //////////////////////////////
454 RenderSurface* newSurface = ShouldSurfaceBeReplaced();
455 if( DALI_UNLIKELY( newSurface ) )
457 LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
458 mRenderHelper.ReplaceSurface( newSurface );
462 const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
465 //////////////////////////////
467 //////////////////////////////
469 const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
470 const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
472 uint64_t noOfFramesSinceLastUpdate = 1;
473 float frameDelta = 0.0f;
476 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
477 noOfFramesSinceLastUpdate += extraFramesDropped;
479 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
481 LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
483 Integration::UpdateStatus updateStatus;
485 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
486 mCore.Update( frameDelta,
492 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
494 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
496 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
497 if( updateStatus.NeedsNotification() )
499 mNotificationTrigger.Trigger();
500 LOG_UPDATE_RENDER( "Notification Triggered" );
504 bool surfaceResized = ShouldSurfaceBeResized();
505 if( DALI_UNLIKELY( surfaceResized ) )
507 // RenderHelper::ResizeSurface() should be called right after a viewport is changed.
508 if( updateStatus.SurfaceRectChanged() )
510 LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
511 mRenderHelper.ResizeSurface();
516 // Optional logging of update/render status
517 mUpdateStatusLogger.Log( keepUpdatingStatus );
519 //////////////////////////////
521 //////////////////////////////
523 mRenderHelper.ConsumeEvents();
524 if( mPreRenderCallback != NULL )
526 bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
529 delete mPreRenderCallback;
530 mPreRenderCallback = NULL;
533 mRenderHelper.PreRender();
535 Integration::RenderStatus renderStatus;
537 AddPerformanceMarker( PerformanceInterface::RENDER_START );
538 mCore.Render( renderStatus, mForceClear );
539 AddPerformanceMarker( PerformanceInterface::RENDER_END );
543 if( renderStatus.NeedsPostRender() )
545 mRenderHelper.PostRender( isRenderingToFbo );
548 // Trigger event thread to request Update/Render thread to sleep if update not required
549 if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
550 ! renderStatus.NeedsUpdate() )
552 mSleepTrigger->Trigger();
553 updateRequired = false;
554 LOG_UPDATE_RENDER( "Sleep Triggered" );
558 updateRequired = true;
561 //////////////////////////////
563 //////////////////////////////
565 extraFramesDropped = 0;
567 if (timeToSleepUntil == 0)
569 // If this is the first frame after the thread is initialized or resumed, we
570 // use the actual time the current frame starts from to calculate the time to
571 // sleep until the next frame.
572 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
576 // Otherwise, always use the sleep-until time calculated in the last frame to
577 // calculate the time to sleep until the next frame. In this way, if there is
578 // any time gap between the current frame and the next frame, or if update or
579 // rendering in the current frame takes too much time so that the specified
580 // sleep-until time has already passed, it will try to keep the frames syncing
581 // by shortening the duration of the next frame.
582 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
584 // Check the current time at the end of the frame
585 uint64_t currentFrameEndTime = 0;
586 TimeService::GetNanoseconds( currentFrameEndTime );
587 while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
589 // We are more than one frame behind already, so just drop the next frames
590 // until the sleep-until time is later than the current time so that we can
592 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
593 extraFramesDropped++;
597 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
598 if( 0u == renderToFboInterval )
600 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
601 TimeService::SleepUntil( timeToSleepUntil );
605 // Inform core of context destruction & shutdown EGL
606 mCore.ContextDestroyed();
607 mRenderHelper.ShutdownEgl();
609 LOG_UPDATE_RENDER( "THREAD DESTROYED" );
611 // Uninstall the logging function
612 mEnvironmentOptions.UnInstallLogFunction();
615 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
617 useElapsedTime = true;
619 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
620 while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
621 ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
622 ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
623 ! mNewSurface && // Ensure we don't wait if we need to replace the surface
624 ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
626 LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
627 LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
628 LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
629 LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
630 LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
632 // Reset the time when the thread is waiting, so the sleep-until time for
633 // the first frame after resuming should be based on the actual start time
634 // of the first frame.
635 timeToSleepUntil = 0;
637 mUpdateRenderThreadWaitCondition.Wait( updateLock );
639 if( ! mUseElapsedTimeAfterWait )
641 useElapsedTime = false;
645 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
646 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
647 LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
648 LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
649 LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
651 mUseElapsedTimeAfterWait = FALSE;
652 mUpdateRenderThreadCanSleep = FALSE;
653 mPendingRequestUpdate = FALSE;
655 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
656 // requested number of cycles
657 if( mUpdateRenderRunCount > 0 )
659 --mUpdateRenderRunCount;
662 // Keep the update-render thread alive if this thread is NOT to be destroyed
663 return ! mDestroyUpdateRenderThread;
666 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
668 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
670 RenderSurface* newSurface = mNewSurface;
676 void CombinedUpdateRenderController::SurfaceReplaced()
678 // Just increment the semaphore
679 sem_post( &mEventThreadSemaphore );
682 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
684 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
685 return mSurfaceResized;
688 void CombinedUpdateRenderController::SurfaceResized()
690 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
691 mSurfaceResized = FALSE;
694 ///////////////////////////////////////////////////////////////////////////////////////////////////
696 ///////////////////////////////////////////////////////////////////////////////////////////////////
698 void CombinedUpdateRenderController::NotifyThreadInitialised()
700 // Just increment the semaphore
701 sem_post( &mEventThreadSemaphore );
704 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
706 if( mPerformanceInterface )
708 mPerformanceInterface->AddMarker( type );
712 /////////////////////////////////////////////////////////////////////////////////////////////////
713 // POST RENDERING: EVENT THREAD
714 /////////////////////////////////////////////////////////////////////////////////////////////////
716 void CombinedUpdateRenderController::PostRenderComplete()
718 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
719 mPostRendering = FALSE;
720 mUpdateRenderThreadWaitCondition.Notify( lock );
723 ///////////////////////////////////////////////////////////////////////////////////////////////////
724 // POST RENDERING: RENDER THREAD
725 ///////////////////////////////////////////////////////////////////////////////////////////////////
727 void CombinedUpdateRenderController::PostRenderStarted()
729 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
730 mPostRendering = TRUE;
733 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
735 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
736 while( mPostRendering &&
737 ! mNewSurface && // We should NOT wait if we're replacing the surface
738 ! mSurfaceResized && // We should NOT wait if we're resizing the surface
739 ! mDestroyUpdateRenderThread )
741 mUpdateRenderThreadWaitCondition.Wait( lock );
745 } // namespace Adaptor
747 } // namespace Internal