2 * Copyright (c) 2017 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>
43 const unsigned int CREATED_THREAD_COUNT = 1u;
45 const int CONTINUOUS = -1;
48 const unsigned int TRUE = 1u;
49 const unsigned int FALSE = 0u;
51 const unsigned int MILLISECONDS_PER_SECOND( 1e+3 );
52 const float NANOSECONDS_TO_SECOND( 1e-9f );
53 const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
54 const unsigned int NANOSECONDS_PER_MILLISECOND( 1e+6 );
56 // The following values will get calculated at compile time
57 const float DEFAULT_FRAME_DURATION_IN_SECONDS( 1.0f / 60.0f );
58 const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * MILLISECONDS_PER_SECOND );
59 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * NANOSECONDS_PER_SECOND );
62 * 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
63 * there is a danger that, on the event-thread we could have:
64 * 1) An update-request where we do nothing as Update/Render thread still running.
65 * 2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
67 * 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:
68 * 1) MAIN THREAD: Update Request: COUNTER = 1
69 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
70 * 3) MAIN THREAD: Update Request: COUNTER = 2
71 * 4) MAIN THREAD: Sleep Request: COUNTER = 1 -> We do not sleep just yet
73 * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
74 * 1) MAIN THREAD: Update Request: COUNTER = 1
75 * 2) UPDATE/RENDER THREAD: Do Update/Render, then no Updates required -> Sleep Trigger
76 * 3) MAIN THREAD: Sleep Request: COUNTER = 0 -> Go to sleep
78 const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
79 } // unnamed namespace
81 ///////////////////////////////////////////////////////////////////////////////////////////////////
83 ///////////////////////////////////////////////////////////////////////////////////////////////////
85 CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
86 : mFpsTracker( environmentOptions ),
87 mUpdateStatusLogger( environmentOptions ),
88 mRenderHelper( adaptorInterfaces ),
89 mEventThreadSemaphore(),
90 mUpdateRenderThreadWaitCondition(),
91 mAdaptorInterfaces( adaptorInterfaces ),
92 mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
93 mCore( adaptorInterfaces.GetCore() ),
94 mEnvironmentOptions( environmentOptions ),
95 mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
96 mSleepTrigger( NULL ),
97 mUpdateRenderThread( NULL ),
98 mDefaultFrameDelta( 0.0f ),
99 mDefaultFrameDurationMilliseconds( 0u ),
100 mDefaultFrameDurationNanoseconds( 0u ),
101 mDefaultHalfFrameNanoseconds( 0u ),
102 mUpdateRequestCount( 0u ),
104 mUpdateRenderRunCount( 0 ),
105 mDestroyUpdateRenderThread( FALSE ),
106 mUpdateRenderThreadCanSleep( FALSE ),
107 mPendingRequestUpdate( FALSE ),
108 mUseElapsedTimeAfterWait( FALSE ),
110 mPostRendering( FALSE ),
111 mSurfaceResized( FALSE )
115 // Initialise frame delta/duration variables first
116 SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
118 // Set the thread-synchronization interface on the render-surface
119 RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
122 currentSurface->SetThreadSynchronization( *this );
125 TriggerEventFactoryInterface& triggerFactory = mAdaptorInterfaces.GetTriggerEventFactoryInterface();
126 mSleepTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
128 sem_init( &mEventThreadSemaphore, 0, 0 ); // Initialize to 0 so that it just waits if sem_post has not been called
131 CombinedUpdateRenderController::~CombinedUpdateRenderController()
137 delete mSleepTrigger;
140 void CombinedUpdateRenderController::Initialize()
144 // Ensure Update/Render Thread not already created
145 DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
147 // Create Update/Render Thread
148 mUpdateRenderThread = new pthread_t();
149 int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
150 DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
152 // The Update/Render thread will now run and initialise EGL etc. and will then wait for Start to be called
153 // When this function returns, the application initialisation on the event thread should occur
156 void CombinedUpdateRenderController::Start()
160 DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
162 // Wait until all threads created in Initialise are up and running
163 for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
165 sem_wait( &mEventThreadSemaphore );
168 mRenderHelper.Start();
172 LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
174 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
177 void CombinedUpdateRenderController::Pause()
183 PauseUpdateRenderThread();
185 AddPerformanceMarker( PerformanceInterface::PAUSED );
188 void CombinedUpdateRenderController::Resume()
192 if( !mRunning && IsUpdateRenderThreadPaused() )
194 LOG_EVENT( "Resuming" );
196 RunUpdateRenderThread( CONTINUOUS, true /* Animation progression required while we were paused */ );
198 AddPerformanceMarker( PerformanceInterface::RESUME );
204 void CombinedUpdateRenderController::Stop()
208 // Stop Rendering and the Update/Render Thread
209 mRenderHelper.Stop();
211 StopUpdateRenderThread();
213 if( mUpdateRenderThread )
215 LOG_EVENT( "Destroying UpdateRenderThread" );
217 // wait for the thread to finish
218 pthread_join( *mUpdateRenderThread, NULL );
220 delete mUpdateRenderThread;
221 mUpdateRenderThread = NULL;
227 void CombinedUpdateRenderController::RequestUpdate()
231 // Increment the update-request count to the maximum
232 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
234 ++mUpdateRequestCount;
237 if( mRunning && IsUpdateRenderThreadPaused() )
239 LOG_EVENT( "Processing" );
241 RunUpdateRenderThread( CONTINUOUS, false /* No animation progression */ );
244 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
245 mPendingRequestUpdate = TRUE;
248 void CombinedUpdateRenderController::RequestUpdateOnce()
250 // Increment the update-request count to the maximum
251 if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
253 ++mUpdateRequestCount;
256 if( IsUpdateRenderThreadPaused() )
260 // Run Update/Render once
261 RunUpdateRenderThread( ONCE, false /* No animation progression */ );
265 void CombinedUpdateRenderController::ReplaceSurface( RenderSurface* newSurface )
269 // Set the ThreadSyncronizationInterface on the new surface
270 newSurface->SetThreadSynchronization( *this );
272 LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
274 // Start replacing the surface.
276 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
277 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
278 mNewSurface = newSurface;
279 mUpdateRenderThreadWaitCondition.Notify( lock );
282 // Wait until the surface has been replaced
283 sem_wait( &mEventThreadSemaphore );
285 LOG_EVENT( "Surface replaced, event-thread continuing" );
288 void CombinedUpdateRenderController::ResizeSurface()
292 LOG_EVENT( "Starting to resize the surface, event-thread blocked" );
294 // Start resizing the surface.
296 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
297 mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
298 mSurfaceResized = TRUE;
299 mUpdateRenderThreadWaitCondition.Notify( lock );
302 // Wait until the surface has been resized
303 sem_wait( &mEventThreadSemaphore );
305 LOG_EVENT( "Surface resized, event-thread continuing" );
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 ///////////////////////////////////////////////////////////////////////////////////////////////////
321 ///////////////////////////////////////////////////////////////////////////////////////////////////
323 void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, bool useElapsedTime )
325 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
326 mUpdateRenderRunCount = numberOfCycles;
327 mUpdateRenderThreadCanSleep = FALSE;
328 mUseElapsedTimeAfterWait = useElapsedTime;
329 LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
330 mUpdateRenderThreadWaitCondition.Notify( lock );
333 void CombinedUpdateRenderController::PauseUpdateRenderThread()
335 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
336 mUpdateRenderRunCount = 0;
339 void CombinedUpdateRenderController::StopUpdateRenderThread()
341 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
342 mDestroyUpdateRenderThread = TRUE;
343 mUpdateRenderThreadWaitCondition.Notify( lock );
346 bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
348 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
349 return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
350 mUpdateRenderThreadCanSleep; // Report paused if sleeping
353 void CombinedUpdateRenderController::ProcessSleepRequest()
357 // Decrement Update request count
358 if( mUpdateRequestCount > 0 )
360 --mUpdateRequestCount;
363 // Can sleep if our update-request count is 0
364 // Update/Render thread can choose to carry on updating if it determines more update/renders are required
365 if( mUpdateRequestCount == 0 )
367 LOG_EVENT( "Going to sleep" );
369 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
370 mUpdateRenderThreadCanSleep = TRUE;
374 ///////////////////////////////////////////////////////////////////////////////////////////////////
375 // UPDATE/RENDER THREAD
376 ///////////////////////////////////////////////////////////////////////////////////////////////////
378 void CombinedUpdateRenderController::UpdateRenderThread()
380 // Install a function for logging
381 mEnvironmentOptions.InstallLogFunction();
383 LOG_UPDATE_RENDER( "THREAD CREATED" );
385 mRenderHelper.InitializeEgl();
387 // tell core it has a context
388 mCore.ContextCreated();
390 NotifyThreadInitialised();
393 uint64_t lastFrameTime;
394 TimeService::GetNanoseconds( lastFrameTime );
396 LOG_UPDATE_RENDER( "THREAD INITIALISED" );
398 bool useElapsedTime = true;
399 bool updateRequired = true;
400 uint64_t timeToSleepUntil = 0;
401 int extraFramesDropped = 0;
403 const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
404 const bool renderToFboEnabled = 0u != renderToFboInterval;
405 unsigned int frameCount = 0u;
407 while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
409 LOG_UPDATE_RENDER_TRACE;
411 // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
412 AddPerformanceMarker( PerformanceInterface::VSYNC );
414 uint64_t currentFrameStartTime = 0;
415 TimeService::GetNanoseconds( currentFrameStartTime );
417 const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
419 // Optional FPS Tracking when continuously rendering
420 if( useElapsedTime && mFpsTracker.Enabled() )
422 float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
423 mFpsTracker.Track( absoluteTimeSinceLastRender );
426 lastFrameTime = currentFrameStartTime; // Store frame start time
428 //////////////////////////////
430 //////////////////////////////
432 RenderSurface* newSurface = ShouldSurfaceBeReplaced();
433 if( DALI_UNLIKELY( newSurface ) )
435 LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
436 mRenderHelper.ReplaceSurface( newSurface );
440 //////////////////////////////
442 //////////////////////////////
444 const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
447 // The resizing will be applied in the next loop
448 bool surfaceResized = ShouldSurfaceBeResized();
449 if( DALI_UNLIKELY( surfaceResized ) )
451 LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
452 mRenderHelper.ResizeSurface();
456 //////////////////////////////
458 //////////////////////////////
460 const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
461 const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
463 uint64_t noOfFramesSinceLastUpdate = 1;
464 float frameDelta = 0.0f;
467 // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
468 noOfFramesSinceLastUpdate += extraFramesDropped;
470 frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
472 LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
474 Integration::UpdateStatus updateStatus;
476 AddPerformanceMarker( PerformanceInterface::UPDATE_START );
477 mCore.Update( frameDelta,
483 AddPerformanceMarker( PerformanceInterface::UPDATE_END );
485 unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
487 // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
488 if( updateStatus.NeedsNotification() )
490 mNotificationTrigger.Trigger();
491 LOG_UPDATE_RENDER( "Notification Triggered" );
494 // Optional logging of update/render status
495 mUpdateStatusLogger.Log( keepUpdatingStatus );
497 //////////////////////////////
499 //////////////////////////////
501 mRenderHelper.ConsumeEvents();
502 mRenderHelper.PreRender();
504 Integration::RenderStatus renderStatus;
506 AddPerformanceMarker( PerformanceInterface::RENDER_START );
507 mCore.Render( renderStatus );
508 AddPerformanceMarker( PerformanceInterface::RENDER_END );
510 if( renderStatus.NeedsPostRender() )
512 mRenderHelper.PostRender( isRenderingToFbo );
515 // Trigger event thread to request Update/Render thread to sleep if update not required
516 if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) &&
517 ! renderStatus.NeedsUpdate() )
519 mSleepTrigger->Trigger();
520 updateRequired = false;
521 LOG_UPDATE_RENDER( "Sleep Triggered" );
525 updateRequired = true;
528 //////////////////////////////
530 //////////////////////////////
532 extraFramesDropped = 0;
534 if (timeToSleepUntil == 0)
536 // If this is the first frame after the thread is initialized or resumed, we
537 // use the actual time the current frame starts from to calculate the time to
538 // sleep until the next frame.
539 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
543 // Otherwise, always use the sleep-until time calculated in the last frame to
544 // calculate the time to sleep until the next frame. In this way, if there is
545 // any time gap between the current frame and the next frame, or if update or
546 // rendering in the current frame takes too much time so that the specified
547 // sleep-until time has already passed, it will try to keep the frames syncing
548 // by shortening the duration of the next frame.
549 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
551 // Check the current time at the end of the frame
552 uint64_t currentFrameEndTime = 0;
553 TimeService::GetNanoseconds( currentFrameEndTime );
554 while ( currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds )
556 // We are more than one frame behind already, so just drop the next frames
557 // until the sleep-until time is later than the current time so that we can
559 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
560 extraFramesDropped++;
564 // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
565 if( 0u == renderToFboInterval )
567 // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
568 TimeService::SleepUntil( timeToSleepUntil );
572 // Inform core of context destruction & shutdown EGL
573 mCore.ContextDestroyed();
574 mRenderHelper.ShutdownEgl();
576 LOG_UPDATE_RENDER( "THREAD DESTROYED" );
578 // Uninstall the logging function
579 mEnvironmentOptions.UnInstallLogFunction();
582 bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
584 useElapsedTime = true;
586 ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
587 while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
588 ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
589 ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
590 ! mNewSurface && // Ensure we don't wait if we need to replace the surface
591 ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
593 LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
594 LOG_UPDATE_RENDER( " mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
595 LOG_UPDATE_RENDER( " mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
596 LOG_UPDATE_RENDER( " mNewSurface: %d", mNewSurface );
597 LOG_UPDATE_RENDER( " mSurfaceResized: %d", mSurfaceResized );
599 // Reset the time when the thread is waiting, so the sleep-until time for
600 // the first frame after resuming should be based on the actual start time
601 // of the first frame.
602 timeToSleepUntil = 0;
604 mUpdateRenderThreadWaitCondition.Wait( updateLock );
606 if( ! mUseElapsedTimeAfterWait )
608 useElapsedTime = false;
612 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount: %d", mUpdateRenderRunCount );
613 LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
614 LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread: %d", mDestroyUpdateRenderThread );
615 LOG_COUNTER_UPDATE_RENDER( "mNewSurface: %d", mNewSurface );
616 LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized: %d", mSurfaceResized );
618 mUseElapsedTimeAfterWait = FALSE;
619 mUpdateRenderThreadCanSleep = FALSE;
620 mPendingRequestUpdate = FALSE;
622 // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
623 // requested number of cycles
624 if( mUpdateRenderRunCount > 0 )
626 --mUpdateRenderRunCount;
629 // Keep the update-render thread alive if this thread is NOT to be destroyed
630 return ! mDestroyUpdateRenderThread;
633 RenderSurface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
635 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
637 RenderSurface* newSurface = mNewSurface;
643 void CombinedUpdateRenderController::SurfaceReplaced()
645 // Just increment the semaphore
646 sem_post( &mEventThreadSemaphore );
649 bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
651 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
653 bool surfaceSized = mSurfaceResized;
654 mSurfaceResized = FALSE;
659 void CombinedUpdateRenderController::SurfaceResized()
661 // Just increment the semaphore
662 sem_post( &mEventThreadSemaphore );
665 ///////////////////////////////////////////////////////////////////////////////////////////////////
667 ///////////////////////////////////////////////////////////////////////////////////////////////////
669 void CombinedUpdateRenderController::NotifyThreadInitialised()
671 // Just increment the semaphore
672 sem_post( &mEventThreadSemaphore );
675 void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
677 if( mPerformanceInterface )
679 mPerformanceInterface->AddMarker( type );
683 /////////////////////////////////////////////////////////////////////////////////////////////////
684 // POST RENDERING: EVENT THREAD
685 /////////////////////////////////////////////////////////////////////////////////////////////////
687 void CombinedUpdateRenderController::PostRenderComplete()
689 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
690 mPostRendering = FALSE;
691 mUpdateRenderThreadWaitCondition.Notify( lock );
694 ///////////////////////////////////////////////////////////////////////////////////////////////////
695 // POST RENDERING: RENDER THREAD
696 ///////////////////////////////////////////////////////////////////////////////////////////////////
698 void CombinedUpdateRenderController::PostRenderStarted()
700 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
701 mPostRendering = TRUE;
704 void CombinedUpdateRenderController::PostRenderWaitForCompletion()
706 ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
707 while( mPostRendering &&
708 ! mNewSurface && // We should NOT wait if we're replacing the surface
709 ! mSurfaceResized && // We should NOT wait if we're resizing the surface
710 ! mDestroyUpdateRenderThread )
712 mUpdateRenderThreadWaitCondition.Wait( lock );
716 } // namespace Adaptor
718 } // namespace Internal