Render to Frame Buffer Object. 77/155577/12
authorVictor Cebollada <v.cebollada@samsung.com>
Thu, 12 Oct 2017 15:36:42 +0000 (16:36 +0100)
committerVictor Cebollada <v.cebollada@samsung.com>
Wed, 1 Nov 2017 09:44:57 +0000 (09:44 +0000)
* A new feature has been added to dali-core/dali-adaptor to
  measure the performance above 60 fps avoiding the vsync.

  It renders the frames into a Frame Buffer Object. However,
  is possible to render into the default Frame Buffer every
  certain number of frames.

* Usage: $ DALI_FPS_TRACKING=1 DALI_RENDER_TO_FBO=30 path_to_DALi_app

  Will render into the Frame Buffer Object 29 frames of 30, the 30th
  will be rendered into the Frame Buffer. Will show as well the FPS.

Change-Id: I3a56078e5ec97ffda781a1242576dda25d148110
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
adaptors/base/combined-update-render/combined-update-render-controller.cpp
adaptors/base/environment-options.cpp
adaptors/base/environment-options.h
adaptors/base/environment-variables.h
adaptors/base/render-helper.cpp
adaptors/base/render-helper.h
adaptors/common/adaptor-impl.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp

index 2b3ed58..9bb5bdc 100644 (file)
@@ -400,6 +400,10 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   uint64_t timeToSleepUntil = 0;
   int extraFramesDropped = 0;
 
+  const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
+  const bool renderToFboEnabled = 0u != renderToFboInterval;
+  unsigned int frameCount = 0u;
+
   while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
   {
     LOG_UPDATE_RENDER_TRACE;
@@ -437,6 +441,9 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     // RESIZE SURFACE
     //////////////////////////////
 
+    const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
+    ++frameCount;
+
     // The resizing will be applied in the next loop
     bool surfaceResized = ShouldSurfaceBeResized();
     if( DALI_UNLIKELY( surfaceResized ) )
@@ -467,7 +474,12 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     Integration::UpdateStatus updateStatus;
 
     AddPerformanceMarker( PerformanceInterface::UPDATE_START );
-    mCore.Update( frameDelta, currentTime, nextFrameTime, updateStatus );
+    mCore.Update( frameDelta,
+                  currentTime,
+                  nextFrameTime,
+                  updateStatus,
+                  renderToFboEnabled,
+                  isRenderingToFbo );
     AddPerformanceMarker( PerformanceInterface::UPDATE_END );
 
     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
@@ -497,7 +509,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
 
     if( renderStatus.NeedsPostRender() )
     {
-      mRenderHelper.PostRender();
+      mRenderHelper.PostRender( isRenderingToFbo );
     }
 
     // Trigger event thread to request Update/Render thread to sleep if update not required
@@ -549,8 +561,12 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       }
     }
 
-    // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
-    TimeService::SleepUntil( timeToSleepUntil );
+    // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
+    if( 0u == renderToFboInterval )
+    {
+      // Sleep until at least the the default frame duration has elapsed. This will return immediately if the specified end-time has already passed.
+      TimeService::SleepUntil( timeToSleepUntil );
+    }
   }
 
   // Inform core of context destruction & shutdown EGL
index 5310615..13e102b 100644 (file)
@@ -103,14 +103,15 @@ EnvironmentOptions::EnvironmentOptions()
   mPanMinimumDistance(-1),
   mPanMinimumEvents(-1),
   mGlesCallTime( 0 ),
-  mWindowWidth( 0 ),
-  mWindowHeight( 0 ),
+  mWindowWidth( 0u ),
+  mWindowHeight( 0u ),
   mThreadingMode( ThreadingMode::COMBINED_UPDATE_RENDER ),
-  mRenderRefreshRate( 1 ),
+  mRenderRefreshRate( 1u ),
   mGlesCallAccumulate( false ),
   mMultiSamplingLevel( DEFAULT_MULTI_SAMPLING_LEVEL ),
   mMaxTextureSize( 0 ),
   mIndicatorVisibleMode( -1 ),
+  mRenderToFboInterval( 0u ),
   mLogFunction( NULL )
 {
   ParseEnvironmentOptions();
@@ -272,6 +273,11 @@ int EnvironmentOptions::GetIndicatorVisibleMode() const
   return mIndicatorVisibleMode;
 }
 
+unsigned int EnvironmentOptions::GetRenderToFboInterval() const
+{
+  return mRenderToFboInterval;
+}
+
 bool EnvironmentOptions::PerformanceServerRequired() const
 {
   return ( ( GetPerformanceStatsLoggingOptions() > 0) ||
@@ -437,6 +443,8 @@ void EnvironmentOptions::ParseEnvironmentOptions()
       mIndicatorVisibleMode = indicatorVisibleMode;
     }
   }
+
+  mRenderToFboInterval = GetIntegerEnvironmentVariable( DALI_RENDER_TO_FBO, 0u );
 }
 
 } // Adaptor
index 2d2300d..080850e 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H__
-#define __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H__
+#ifndef DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H
+#define DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H
 
 /*
  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
@@ -217,6 +217,13 @@ public:
    */
   int GetIndicatorVisibleMode() const;
 
+  /**
+   * @brief Retrieves the interval of frames to be rendered into the Frame Buffer Object and the Frame Buffer.
+   *
+   * @return The number of frames that are going to be rendered into the Frame Buffer Object but the last one which is going to be rendered into the Frame Buffer.
+   */
+  unsigned int GetRenderToFboInterval() const;
+
 private: // Internal
 
   /**
@@ -255,6 +262,7 @@ private: // Data
   int mMultiSamplingLevel;                        ///< The number of samples required in multisample buffers
   unsigned int mMaxTextureSize;                   ///< The maximum texture size that GL can handle
   int mIndicatorVisibleMode;                      ///< Indicator visible mode
+  unsigned int mRenderToFboInterval;              ///< The number of frames that are going to be rendered into the Frame Buffer Object but the last one which is going to be rendered into the Frame Buffer.
 
   Dali::Integration::Log::LogFunction mLogFunction;
 
@@ -270,4 +278,4 @@ private: // Data
 } // Internal
 } // Dali
 
-#endif // __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H__
+#endif // DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H
index 72b4834..234ce3c 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H__
-#define __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H__
+#ifndef DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H
+#define DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H
 
 /*
  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
@@ -99,10 +99,12 @@ namespace Adaptor
 
 #define DALI_ENV_INDICATOR_VISIBLE_MODE "DALI_INDICATOR_VISIBLE_MODE"
 
+#define DALI_RENDER_TO_FBO "DALI_RENDER_TO_FBO"
+
 } // namespace Adaptor
 
 } // namespace Internal
 
 } // namespace Dali
 
-#endif // __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H__
+#endif // DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H
index c77d2c9..1276078 100644 (file)
@@ -155,15 +155,23 @@ bool RenderHelper::PreRender()
   return true;
 }
 
-void RenderHelper::PostRender()
+void RenderHelper::PostRender( bool renderToFbo )
 {
   // Inform the gl implementation that rendering has finished before informing the surface
   mGLES.PostRender();
 
-  if( mSurface )
+  if( renderToFbo )
+  {
+    mGLES.Flush();
+    mGLES.Finish();
+  }
+  else
   {
-    // Inform the surface that rendering this frame has finished.
-    mSurface->PostRender( *mEGL, mGLES, mDisplayConnection, mSurfaceReplaced, mSurfaceResized );
+    if( mSurface )
+    {
+      // Inform the surface that rendering this frame has finished.
+      mSurface->PostRender( *mEGL, mGLES, mDisplayConnection, mSurfaceReplaced, mSurfaceResized );
+    }
   }
   mSurfaceReplaced = false;
   mSurfaceResized = false;
index 5d26d16..4e12afe 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __DALI_INTERNAL_RENDER_HELPER_H__
-#define __DALI_INTERNAL_RENDER_HELPER_H__
+#ifndef DALI_INTERNAL_RENDER_HELPER_H
+#define DALI_INTERNAL_RENDER_HELPER_H
 
 /*
  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
@@ -128,8 +128,10 @@ public:
    * Called after core has rendered the scene
    *
    * @note Called from render thread
+   *
+   * @param[in] renderToFbo Whether to render to a Frame Buffer Object.
    */
-  void PostRender();
+  void PostRender( bool renderToFbo );
 
 private:
 
@@ -156,4 +158,4 @@ private: // Data
 
 } // namespace Dali
 
-#endif // __DALI_INTERNAL_RENDER_HELPER_H__
+#endif // DALI_INTERNAL_RENDER_HELPER_H
index e4b508f..2827310 100644 (file)
@@ -142,7 +142,13 @@ void Adaptor::Initialize( Dali::Configuration::ContextLoss configuration )
 
   EglSyncImplementation* eglSyncImpl = mEglFactory->GetSyncImplementation();
 
-  mCore = Integration::Core::New( *this, *mPlatformAbstraction, *mGLES, *eglSyncImpl, *mGestureManager, dataRetentionPolicy );
+  mCore = Integration::Core::New( *this,
+                                  *mPlatformAbstraction,
+                                  *mGLES,
+                                  *eglSyncImpl,
+                                  *mGestureManager,
+                                  dataRetentionPolicy ,
+                                  0u != mEnvironmentOptions->GetRenderToFboInterval() );
 
   const unsigned int timeInterval = mEnvironmentOptions->GetObjectProfilerInterval();
   if( 0u < timeInterval )
index 6636676..54a69bb 100644 (file)
@@ -62,13 +62,13 @@ void TestApplication::Initialize()
   // We always need the first update!
   mStatus.keepUpdating = Integration::KeepUpdating::STAGE_KEEP_RENDERING;
 
-  mCore = Dali::Integration::Core::New(
-    mRenderController,
-    mPlatformAbstraction,
-    mGlAbstraction,
-    mGlSyncAbstraction,
-    mGestureManager,
-    mDataRetentionPolicy);
+  mCore = Dali::Integration::Core::New( mRenderController,
+                                        mPlatformAbstraction,
+                                        mGlAbstraction,
+                                        mGlSyncAbstraction,
+                                        mGestureManager,
+                                        mDataRetentionPolicy,
+                                        false );
 
   mCore->ContextCreated();
   mCore->SurfaceResized( mSurfaceWidth, mSurfaceHeight );
@@ -171,7 +171,7 @@ void TestApplication::DoUpdate( unsigned int intervalMilliseconds, const char* l
   unsigned int nextVSyncTime = mLastVSyncTime + intervalMilliseconds;
   float elapsedSeconds = intervalMilliseconds / 1e3f;
 
-  mCore->Update( elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus );
+  mCore->Update( elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus, false, false );
 
   GetRenderController().Initialize();