// EVENT THREAD
///////////////////////////////////////////////////////////////////////////////////////////////////
-CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
+CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions, ThreadMode threadMode )
: mFpsTracker( environmentOptions ),
mUpdateStatusLogger( environmentOptions ),
mEventThreadSemaphore(),
mDefaultHalfFrameNanoseconds( 0u ),
mUpdateRequestCount( 0u ),
mRunning( FALSE ),
+ mThreadMode( threadMode ),
mUpdateRenderRunCount( 0 ),
mDestroyUpdateRenderThread( FALSE ),
mUpdateRenderThreadCanSleep( FALSE ),
++mUpdateRequestCount;
}
- if( IsUpdateRenderThreadPaused() )
+ if( IsUpdateRenderThreadPaused() || updateMode == UpdateMode::FORCE_RENDER )
{
LOG_EVENT_TRACE;
void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode )
{
ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
- mUpdateRenderRunCount = numberOfCycles;
+
+ switch( mThreadMode )
+ {
+ case ThreadMode::NORMAL:
+ {
+ mUpdateRenderRunCount = numberOfCycles;
+ mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
+ break;
+ }
+ case ThreadMode::RUN_IF_REQUESTED:
+ {
+ if( updateMode != UpdateMode::FORCE_RENDER )
+ {
+ // Render only if the update mode is FORCE_RENDER which means the application requests it.
+ // We don't want to awake the update thread.
+ return;
+ }
+
+ mUpdateRenderRunCount++; // Increase the update request count
+ mUseElapsedTimeAfterWait = TRUE; // The elapsed time should be used. We want animations to proceed.
+ break;
+ }
+ }
+
mUpdateRenderThreadCanSleep = FALSE;
- mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
mUploadWithoutRendering = ( updateMode == UpdateMode::SKIP_RENDER );
LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
mUpdateRenderThreadWaitCondition.Notify( lock );
bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
{
ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+
+ if( mThreadMode == ThreadMode::RUN_IF_REQUESTED )
+ {
+ return !mRunning || mUpdateRenderThreadCanSleep;
+ }
+
return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
mUpdateRenderThreadCanSleep; // Report paused if sleeping
}
uint64_t currentFrameStartTime = 0;
TimeService::GetNanoseconds( currentFrameStartTime );
- const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
+ uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
// Optional FPS Tracking when continuously rendering
if( useElapsedTime && mFpsTracker.Enabled() )
float frameDelta = 0.0f;
if( useElapsedTime )
{
+ if( mThreadMode == ThreadMode::RUN_IF_REQUESTED )
+ {
+ extraFramesDropped = 0;
+ while( timeSinceLastFrame >= mDefaultFrameDurationNanoseconds )
+ {
+ timeSinceLastFrame -= mDefaultFrameDurationNanoseconds;
+ extraFramesDropped++;
+ }
+ }
+
// If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
noOfFramesSinceLastUpdate += extraFramesDropped;
if ( scene && windowSurface )
{
+ Integration::RenderStatus windowRenderStatus;
+
windowSurface->InitializeGraphics();
+ // clear previous frame damaged render items rects, buffer history is tracked on surface level
+ mDamagedRects.clear();
+
+ // Collect damage rects
+ mCore.PreRender( scene, mDamagedRects );
+
// Render off-screen frame buffers first if any
- mCore.RenderScene( scene, true );
+ mCore.RenderScene( windowRenderStatus, scene, true );
+
+ Rect<int> clippingRect; // Empty for fbo rendering
+
+ // Switch to the EGL context of the surface, merge damaged areas for previous frames
+ windowSurface->PreRender( surfaceResized, mDamagedRects, clippingRect ); // Switch GL context
- // Switch to the EGL context of the surface
- windowSurface->PreRender( surfaceResized ); // Switch GL context
+ if (clippingRect.IsEmpty())
+ {
+ mDamagedRects.clear();
+ }
// Render the surface
- mCore.RenderScene( scene, false );
+ mCore.RenderScene( windowRenderStatus, scene, false, clippingRect );
- windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer
+ if( windowRenderStatus.NeedsPostRender() )
+ {
+ windowSurface->PostRender( false, false, surfaceResized, mDamagedRects ); // Swap Buffer with damage
+ }
}
}
}