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 mPreRenderCallback( NULL ),
100 mUpdateRenderThread( NULL ),
101 mDefaultFrameDelta( 0.0f ),
102 mDefaultFrameDurationMilliseconds( 0u ),
103 mDefaultFrameDurationNanoseconds( 0u ),
104 mDefaultHalfFrameNanoseconds( 0u ),
105 mUpdateRequestCount( 0u ),
107 mUpdateRenderRunCount( 0 ),
108 mDestroyUpdateRenderThread( FALSE ),
109 mUpdateRenderThreadCanSleep( FALSE ),
110 mPendingRequestUpdate( FALSE ),
111 mUseElapsedTimeAfterWait( FALSE ),
113 mPostRendering( FALSE ),
114 mSurfaceResized( FALSE ),
119 // Initialise frame delta/duration variables first
120 SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
122 // Set the thread-synchronization interface on the render-surface
123 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
126 currentSurface->SetThreadSynchronization( *this );
129 TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
130 mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
132 sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called
135 CombinedUpdateRenderController::~CombinedUpdateRenderController()
141 delete mPreRenderCallback;
142 delete mSleepTrigger;
145 void CombinedUpdateRenderController::Initialize()
149 // Ensure Update/Render Thread not already created
150 DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
152 // Create Update/Render Thread
153 mUpdateRenderThread = new pthread_t();
154 int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
155 DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
157 // The Update/Render thread will now run and initialise EGL etc. and will then wait for Start to be called
158 // When this function returns, the application initialisation on the event thread should occur
161 void CombinedUpdateRenderController::Start()
165 DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
167 // Wait until all threads created in Initialise are up and running
168 for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
170 sem_wait( &mEventThreadSemaphore );
173 mRenderHelper.Start();
177 LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
179 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
182 void CombinedUpdateRenderController::Pause()
188 PauseUpdateRenderThread();
190 AddPerformanceMarker( PerformanceInterface::PAUSED );
193 void CombinedUpdateRenderController::Resume()
197 if( !mRunning && IsUpdateRenderThreadPaused() )
199 LOG_EVENT( "Resuming" );
201 RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
203 AddPerformanceMarker( PerformanceInterface::RESUME );
210 void CombinedUpdateRenderController::Stop()
214 // Stop Rendering and the Update/Render Thread
215 mRenderHelper.Stop();
217 StopUpdateRenderThread();
219 if( mUpdateRenderThread )
221 LOG_EVENT( "Destroying UpdateRenderThread" );
223 // wait for the thread to finish
224 pthread_join( *mUpdateRenderThread, NULL );
226 delete mUpdateRenderThread;
227 mUpdateRenderThread = NULL;
233 void CombinedUpdateRenderController::RequestUpdate()
237 // Increment the update-request count to the maximum
238 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
240 ++mUpdateRequestCount;
243 if( mRunning && IsUpdateRenderThreadPaused() )
245 LOG_EVENT( "Processing" );
247 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
250 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
251 mPendingRequestUpdate = TRUE;
254 void CombinedUpdateRenderController::RequestUpdateOnce()
256 // Increment the update-request count to the maximum
257 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
259 ++mUpdateRequestCount;
262 if( IsUpdateRenderThreadPaused() )
266 // Run Update/Render once
267 RunUpdateRenderThread( ONCE, false /* No animation progression */ );
271 void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
275 // Set the ThreadSyncronizationInterface on the new surface
276 newSurface->SetThreadSynchronization( *this );
278 LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
280 // Start replacing the surface.
282 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
283 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
284 mNewSurface = newSurface;
285 mUpdateRenderThreadWaitCondition.Notify( lock );
288 // Wait until the surface has been replaced
289 sem_wait( &mEventThreadSemaphore );
291 LOG_EVENT( "Surface replaced, event-thread continuing" );
294 void CombinedUpdateRenderController::ResizeSurface()
298 LOG_EVENT( "Resize the surface" );
301 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
302 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
303 mSurfaceResized = TRUE;
304 mUpdateRenderThreadWaitCondition.Notify( lock );
308 void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
310 // Not protected by lock, but written to rarely so not worth adding a lock when reading
311 mDefaultFrameDelta = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
312 mDefaultFrameDurationMilliseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
313 mDefaultFrameDurationNanoseconds = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
314 mDefaultHalfFrameNanoseconds = mDefaultFrameDurationNanoseconds / 2u;
316 LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
319 void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
322 LOG_EVENT( "Set PreRender Callback" );
324 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
325 if( mPreRenderCallback )
327 delete mPreRenderCallback;
329 mPreRenderCallback = callback;
332 ///////////////////////////////////////////////////////////////////////////////////////////////////
334 ///////////////////////////////////////////////////////////////////////////////////////////////////
336 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
338 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
339 mUpdateRenderRunCount = numberOfCycles;
340 mUpdateRenderThreadCanSleep = FALSE;
341 mUseElapsedTimeAfterWait = useElapsedTime;
342 LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
343 mUpdateRenderThreadWaitCondition.Notify( lock );
346 void CombinedUpdateRenderController::PauseUpdateRenderThread()
348 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
349 mUpdateRenderRunCount = 0;
352 void CombinedUpdateRenderController::StopUpdateRenderThread()
354 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
355 mDestroyUpdateRenderThread = TRUE;
356 mUpdateRenderThreadWaitCondition.Notify( lock );
359 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
361 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
362 return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
363 mUpdateRenderThreadCanSleep; // Report paused if sleeping
366 void CombinedUpdateRenderController::ProcessSleepRequest()
370 // Decrement Update request count
371 if( mUpdateRequestCount > 0 )
373 --mUpdateRequestCount;
376 // Can sleep if our update-request count is 0
377 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
378 if( mUpdateRequestCount == 0 )
380 LOG_EVENT( "Going to sleep" );
382 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
383 mUpdateRenderThreadCanSleep = TRUE;
387 ///////////////////////////////////////////////////////////////////////////////////////////////////
388 // UPDATE/RENDER THREAD
389 ///////////////////////////////////////////////////////////////////////////////////////////////////
391 void CombinedUpdateRenderController::UpdateRenderThread()
393 SetThreadName("RenderThread\0");
395 // Install a function for logging
396 mEnvironmentOptions.InstallLogFunction();
398 // Install a function for tracing
399 mEnvironmentOptions.InstallTraceFunction();
401 LOG_UPDATE_RENDER( "THREAD CREATED" );
403 mRenderHelper.InitializeEgl();
405 // tell core it has a context
406 mCore.ContextCreated();
408 NotifyThreadInitialised();
411 uint64_t lastFrameTime;
412 TimeService::GetNanoseconds( lastFrameTime );
414 LOG_UPDATE_RENDER( "THREAD INITIALISED" );
416 bool useElapsedTime = true;
417 bool updateRequired = true;
418 uint64_t timeToSleepUntil = 0;
419 int extraFramesDropped = 0;
421 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
422 const bool renderToFboEnabled = 0u != renderToFboInterval;
423 unsigned int frameCount = 0u;
425 while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
427 LOG_UPDATE_RENDER_TRACE;
429 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
430 AddPerformanceMarker( PerformanceInterface::VSYNC );
432 uint64_t currentFrameStartTime = 0;
433 TimeService::GetNanoseconds( currentFrameStartTime );
435 const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
437 // Optional FPS Tracking when continuously rendering
438 if( useElapsedTime && mFpsTracker.Enabled() )
440 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
441 mFpsTracker.Track( absoluteTimeSinceLastRender );
444 lastFrameTime = currentFrameStartTime; // Store frame start time
446 //////////////////////////////
448 //////////////////////////////
450 RenderSurface* newSurface = ShouldSurfaceBeReplaced();
451 if( DALI_UNLIKELY( newSurface ) )
453 LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
454 mRenderHelper.ReplaceSurface( newSurface );
458 const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
461 //////////////////////////////
463 //////////////////////////////
465 const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
466 const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
468 uint64_t noOfFramesSinceLastUpdate = 1;
469 float frameDelta = 0.0f;
472 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
473 noOfFramesSinceLastUpdate += extraFramesDropped;
475 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
477 LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
479 Integration::UpdateStatus updateStatus;
481 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
482 mCore.Update( frameDelta,
488 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
490 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
492 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
493 if( updateStatus.NeedsNotification() )
495 mNotificationTrigger.Trigger();
496 LOG_UPDATE_RENDER( "Notification Triggered" );
500 bool surfaceResized = ShouldSurfaceBeResized();
501 if( DALI_UNLIKELY( surfaceResized ) )
503 // RenderHelper::ResizeSurface() should be called right after a viewport is changed.
504 if( updateStatus.SurfaceRectChanged() )
506 LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
507 mRenderHelper.ResizeSurface();
512 // Optional logging of update/render status
513 mUpdateStatusLogger.Log( keepUpdatingStatus );
515 //////////////////////////////
517 //////////////////////////////
519 mRenderHelper.ConsumeEvents();
520 if( mPreRenderCallback != NULL )
522 bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
525 delete mPreRenderCallback;
526 mPreRenderCallback = NULL;
529 mRenderHelper.PreRender();
531 Integration::RenderStatus renderStatus;
533 AddPerformanceMarker( PerformanceInterface::RENDER_START );
534 mCore.Render( renderStatus, mForceClear );
535 AddPerformanceMarker( PerformanceInterface::RENDER_END );
539 if( renderStatus.NeedsPostRender() )
541 mRenderHelper.PostRender( isRenderingToFbo );
544 // Trigger event thread to request Update/Render thread to sleep if update not required
545 if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
546 ! renderStatus.NeedsUpdate() )
548 mSleepTrigger->Trigger();
549 updateRequired = false;
550 LOG_UPDATE_RENDER( "Sleep Triggered" );
554 updateRequired = true;
557 //////////////////////////////
559 //////////////////////////////
561 extraFramesDropped = 0;
563 if (timeToSleepUntil == 0)
565 // If this is the first frame after the thread is initialized or resumed, we
566 // use the actual time the current frame starts from to calculate the time to
567 // sleep until the next frame.
568 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
572 // Otherwise, always use the sleep-until time calculated in the last frame to
573 // calculate the time to sleep until the next frame. In this way, if there is
574 // any time gap between the current frame and the next frame, or if update or
575 // rendering in the current frame takes too much time so that the specified
576 // sleep-until time has already passed, it will try to keep the frames syncing
577 // by shortening the duration of the next frame.
578 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
580 // Check the current time at the end of the frame
581 uint64_t currentFrameEndTime = 0;
582 TimeService::GetNanoseconds( currentFrameEndTime );
583 while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
585 // We are more than one frame behind already, so just drop the next frames
586 // until the sleep-until time is later than the current time so that we can
588 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
589 extraFramesDropped++;
593 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
594 if( 0u == renderToFboInterval )
596 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
597 TimeService::SleepUntil( timeToSleepUntil );
601 // Inform core of context destruction & shutdown EGL
602 mCore.ContextDestroyed();
603 mRenderHelper.ShutdownEgl();
605 LOG_UPDATE_RENDER( "THREAD DESTROYED" );
607 // Uninstall the logging function
608 mEnvironmentOptions.UnInstallLogFunction();
611 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
613 useElapsedTime = true;
615 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
616 while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
617 ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
618 ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
619 ! mNewSurface && // Ensure we don't wait if we need to replace the surface
620 ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
622 LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
623 LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
624 LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
625 LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
626 LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
628 // Reset the time when the thread is waiting, so the sleep-until time for
629 // the first frame after resuming should be based on the actual start time
630 // of the first frame.
631 timeToSleepUntil = 0;
633 mUpdateRenderThreadWaitCondition.Wait( updateLock );
635 if( ! mUseElapsedTimeAfterWait )
637 useElapsedTime = false;
641 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
642 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
643 LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
644 LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
645 LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
647 mUseElapsedTimeAfterWait = FALSE;
648 mUpdateRenderThreadCanSleep = FALSE;
649 mPendingRequestUpdate = FALSE;
651 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
652 // requested number of cycles
653 if( mUpdateRenderRunCount > 0 )
655 --mUpdateRenderRunCount;
658 // Keep the update-render thread alive if this thread is NOT to be destroyed
659 return ! mDestroyUpdateRenderThread;
662 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
664 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
666 RenderSurface* newSurface = mNewSurface;
672 void CombinedUpdateRenderController::SurfaceReplaced()
674 // Just increment the semaphore
675 sem_post( &mEventThreadSemaphore );
678 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
680 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
681 return mSurfaceResized;
684 void CombinedUpdateRenderController::SurfaceResized()
686 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
687 mSurfaceResized = FALSE;
690 ///////////////////////////////////////////////////////////////////////////////////////////////////
692 ///////////////////////////////////////////////////////////////////////////////////////////////////
694 void CombinedUpdateRenderController::NotifyThreadInitialised()
696 // Just increment the semaphore
697 sem_post( &mEventThreadSemaphore );
700 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
702 if( mPerformanceInterface )
704 mPerformanceInterface->AddMarker( type );
708 /////////////////////////////////////////////////////////////////////////////////////////////////
709 // POST RENDERING: EVENT THREAD
710 /////////////////////////////////////////////////////////////////////////////////////////////////
712 void CombinedUpdateRenderController::PostRenderComplete()
714 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
715 mPostRendering = FALSE;
716 mUpdateRenderThreadWaitCondition.Notify( lock );
719 ///////////////////////////////////////////////////////////////////////////////////////////////////
720 // POST RENDERING: RENDER THREAD
721 ///////////////////////////////////////////////////////////////////////////////////////////////////
723 void CombinedUpdateRenderController::PostRenderStarted()
725 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
726 mPostRendering = TRUE;
729 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
731 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
732 while( mPostRendering &&
733 ! mNewSurface && // We should NOT wait if we're replacing the surface
734 ! mSurfaceResized && // We should NOT wait if we're resizing the surface
735 ! mDestroyUpdateRenderThread )
737 mUpdateRenderThreadWaitCondition.Wait( lock );
741 } // namespace Adaptor
743 } // namespace Internal