Support multiple surfaces for partial update 00/242000/4
authorHeeyong Song <heeyong.song@samsung.com>
Fri, 21 Aug 2020 09:02:30 +0000 (18:02 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Thu, 3 Sep 2020 06:26:33 +0000 (15:26 +0900)
Change-Id: I0880ce461407c48bc0290f73fd1bc8824f5e46a8

dali/integration-api/adaptor-framework/render-surface-interface.h
dali/integration-api/adaptor-framework/scene-holder-impl.cpp
dali/internal/graphics/gles/egl-graphics.cpp
dali/internal/graphics/gles/egl-graphics.h
dali/internal/graphics/gles/egl-implementation.cpp
dali/internal/graphics/gles/egl-implementation.h
dali/internal/window-system/common/window-impl.cpp
dali/internal/window-system/common/window-render-surface.cpp
dali/internal/window-system/common/window-render-surface.h
dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.cpp

index 2c7f6b7..2014e89 100644 (file)
@@ -82,6 +82,7 @@ public:
     mGraphics( nullptr ),
     mDisplayConnection( nullptr ),
     mScene(),
+    mFullSwapNextFrame( true ),
     mDepthBufferRequired( Integration::DepthBufferAvailable::FALSE ),
     mStencilBufferRequired( Integration::StencilBufferAvailable::FALSE )
   {}
@@ -220,6 +221,14 @@ public:
     mScene = scene;
   }
 
+  /**
+   * @brief Forces full surface swap next frame, resets current partial update state.
+   */
+  void SetFullSwapNextFrame()
+  {
+    mFullSwapNextFrame = true;
+  }
+
 private:
 
   /**
@@ -238,6 +247,7 @@ protected:
   Dali::Internal::Adaptor::GraphicsInterface* mGraphics;
   Dali::DisplayConnection* mDisplayConnection;
   WeakHandle< Dali::Integration::Scene > mScene;
+  bool mFullSwapNextFrame;                                      ///< Whether the full surface swap is required
 
 private:
 
index e545376..69ce19e 100644 (file)
@@ -214,12 +214,7 @@ void SceneHolder::SurfaceResized()
   PositionSize surfacePositionSize = mSurface->GetPositionSize();
   mScene.SurfaceResized( static_cast<float>( surfacePositionSize.width ), static_cast<float>( surfacePositionSize.height ) );
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 }
 
 Dali::RenderSurfaceInterface* SceneHolder::GetSurface() const
@@ -233,12 +228,7 @@ void SceneHolder::SetBackgroundColor( const Vector4& color )
   {
     mScene.SetBackgroundColor( color );
 
-    GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-    EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-    if (eglGraphics)
-    {
-      eglGraphics->SetFullSwapNextFrame();
-    }
+    mSurface->SetFullSwapNextFrame();
   }
 }
 
index a30abd3..dcbf055 100644 (file)
@@ -129,11 +129,6 @@ EglImageExtensions* EglGraphics::GetImageExtensions()
   return mEglImageExtensions.get();
 }
 
-void EglGraphics::SetFullSwapNextFrame()
-{
-  mEglImplementation->SetFullSwapNextFrame();
-}
-
 } // Adaptor
 } // Internal
 } // Dali
index 5ddfbfb..8ee45bc 100644 (file)
@@ -126,11 +126,6 @@ public:
   EglImageExtensions* GetImageExtensions();
 
   /**
-   * Instructs egl implementation to do full swap regardless of stored data, resets the data.
-   */
-  void SetFullSwapNextFrame();
-
-  /**
    * @copydoc Dali::Internal::Adaptor::GraphicsInterface::Destroy()
    */
   void Destroy() override;
index 6e39644..d674055 100755 (executable)
@@ -87,8 +87,7 @@ EglImplementation::EglImplementation( int multiSamplingLevel,
   mIsKhrCreateContextSupported( false ),
   mSwapBufferCountAfterResume( 0 ),
   mEglSetDamageRegionKHR( 0 ),
-  mEglSwapBuffersWithDamageKHR( 0 ),
-  mFullSwapNextFrame( true )
+  mEglSwapBuffersWithDamageKHR( 0 )
 {
 }
 
@@ -360,7 +359,6 @@ void EglImplementation::SwapBuffers( EGLSurface& eglSurface )
 
     // DALI_LOG_ERROR("EglImplementation::SwapBuffers()\n");
     eglSwapBuffers( mEglDisplay, eglSurface );
-    mFullSwapNextFrame = false;
 
 #ifndef DALI_PROFILE_UBUNTU
     if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
@@ -393,99 +391,19 @@ EGLint EglImplementation::GetBufferAge(EGLSurface& eglSurface) const
   return age;
 }
 
-void EglImplementation::SetFullSwapNextFrame()
+void EglImplementation::SetDamageRegion( EGLSurface& eglSurface, std::vector< Rect< int > >& damagedRects )
 {
-  mFullSwapNextFrame = true;
-}
-
-void mergeRects(Rect<int>& mergingRect, const std::vector<Rect<int>>& rects)
-{
-  uint32_t i = 0;
-  if (mergingRect.IsEmpty())
-  {
-    for (;i < rects.size(); i++)
-    {
-      if (!rects[i].IsEmpty())
-      {
-        mergingRect = rects[i];
-        break;
-      }
-    }
-  }
-
-  for (;i < rects.size(); i++)
-  {
-    mergingRect.Merge(rects[i]);
-  }
-}
-
-void insertRects(std::list<std::vector<Rect<int>>>& damagedRectsList, const std::vector<Rect<int>>& damagedRects)
-{
-  damagedRectsList.push_front(damagedRects);
-  if (damagedRectsList.size() > 4) // past triple buffers + current
-  {
-    damagedRectsList.pop_back();
-  }
-}
-
-void EglImplementation::SetDamage( EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
-{
-  if (!mPartialUpdateRequired)
+  if( !mPartialUpdateRequired )
   {
     return;
   }
 
-  if (eglSurface != EGL_NO_SURFACE) // skip if using surfaceless context
+  if( eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
   {
-    EGLint width = 0;
-    EGLint height = 0;
-    eglQuerySurface(mEglDisplay, eglSurface, EGL_WIDTH, &width);
-    eglQuerySurface(mEglDisplay, eglSurface, EGL_HEIGHT, &height);
-    Rect<int> surfaceRect(0, 0, width, height);
-
-    mSurfaceRect = surfaceRect;
-
-    if (mFullSwapNextFrame)
-    {
-      insertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
-      clippingRect = Rect<int>();
-      return;
-    }
-
-    EGLint bufferAge = GetBufferAge(eglSurface);
-
-    // Buffer age 0 means the back buffer in invalid and requires full swap
-    if (!damagedRects.size() || bufferAge == 0)
-    {
-      // No damage or buffer is out of order or buffer age is reset
-      insertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
-      clippingRect = Rect<int>();
-      return;
-    }
-
-    // We push current frame damaged rects here, zero index for current frame
-    insertRects(mBufferDamagedRects, damagedRects);
-
-    // Merge damaged rects into clipping rect
-    auto bufferDamagedRects = mBufferDamagedRects.begin();
-    while (bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
-    {
-      const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
-      mergeRects(clippingRect, rects);
-    }
-
-    if (!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * 0.8)
-    {
-      // clipping area too big or doesn't intersect surface rect
-      clippingRect = Rect<int>();
-      return;
-    }
-
-    // DALI_LOG_ERROR("eglSetDamageRegionKHR(%d, %d, %d, %d)\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
-    EGLBoolean result = mEglSetDamageRegionKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(&clippingRect), 1);
+    EGLBoolean result = mEglSetDamageRegionKHR( mEglDisplay, eglSurface, reinterpret_cast< int* >( damagedRects.data() ), 1 );
     if (result == EGL_FALSE)
     {
-      DALI_LOG_ERROR("eglSetDamageRegionKHR(%d)\n", eglGetError());
+      DALI_LOG_ERROR( "eglSetDamageRegionKHR(%d)\n", eglGetError() );
     }
   }
 }
@@ -494,7 +412,7 @@ void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Re
 {
   if (eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
   {
-    if (!mPartialUpdateRequired || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > mSurfaceRect.Area() * 0.8) )
+    if (!mPartialUpdateRequired )
     {
       SwapBuffers(eglSurface);
       return;
@@ -507,55 +425,7 @@ void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Re
     }
 #endif //DALI_PROFILE_UBUNTU
 
-    std::vector< Rect< int > > mergedRects = damagedRects;
-
-    // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
-    // Could be optional and can be removed, needs to be checked with and without on platform
-    const int n = mergedRects.size();
-    for(int i = 0; i < n-1; i++)
-    {
-      if (mergedRects[i].IsEmpty())
-      {
-        continue;
-      }
-
-      for (int j = i+1; j < n; j++)
-      {
-        if (mergedRects[j].IsEmpty())
-        {
-          continue;
-        }
-
-        if (mergedRects[i].Intersects(mergedRects[j]))
-        {
-          mergedRects[i].Merge(mergedRects[j]);
-          mergedRects[j].width = 0;
-          mergedRects[j].height = 0;
-        }
-      }
-    }
-
-    int j = 0;
-    for (int i = 0; i < n; i++)
-    {
-      if (!mergedRects[i].IsEmpty())
-      {
-        mergedRects[j++] = mergedRects[i];
-      }
-    }
-
-    if (j != 0)
-    {
-      mergedRects.resize(j);
-    }
-
-    if (!mergedRects.size() || (mergedRects[0].Area() > mSurfaceRect.Area() * 0.8))
-    {
-      SwapBuffers(eglSurface);
-      return;
-    }
-
-    EGLBoolean result = mEglSwapBuffersWithDamageKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(mergedRects.data()), mergedRects.size());
+    EGLBoolean result = mEglSwapBuffersWithDamageKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(const_cast< std::vector< Rect< int > >& >( damagedRects ).data()), damagedRects.size());
     if (result == EGL_FALSE)
     {
       DALI_LOG_ERROR("eglSwapBuffersWithDamageKHR(%d)\n", eglGetError());
@@ -830,6 +700,11 @@ void EglImplementation::WaitClient()
   }
 }
 
+bool EglImplementation::IsPartialUpdateRequired() const
+{
+  return mPartialUpdateRequired;
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index 73d11bb..34d0f5c 100644 (file)
@@ -135,14 +135,9 @@ public:
   EGLint GetBufferAge( EGLSurface& eglSurface ) const;
 
   /**
-   * Forces full surface swap next frame, resets current partial update state.
-   */
-  void SetFullSwapNextFrame();
-
-  /**
    * Performs an OpenGL set damage command with damaged rects
    */
-  virtual void SetDamage( EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect );
+  void SetDamageRegion( EGLSurface& eglSurface, std::vector< Rect< int > >& damagedRects );
 
   /**
    * Performs an OpenGL swap buffers command with damaged rects
@@ -239,6 +234,12 @@ public:
    */
   void WaitClient();
 
+  /**
+   * @brief Returns whether the partial update is required.
+   * @return true if the partial update is required.
+   */
+  bool IsPartialUpdateRequired() const;
+
 private:
 
   Vector<EGLint>       mContextAttribs;
@@ -280,9 +281,6 @@ private:
   PFNEGLSETDAMAGEREGIONKHRPROC mEglSetDamageRegionKHR;
   PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC mEglSwapBuffersWithDamageKHR;
 
-  std::list<std::vector<Rect<int>>> mBufferDamagedRects;
-  Rect<int> mSurfaceRect;
-  bool mFullSwapNextFrame;
 };
 
 } // namespace Adaptor
index be1c3ad..a224207 100755 (executable)
@@ -178,12 +178,7 @@ void Window::Raise()
 {
   mWindowBase->Raise();
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 
   DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Raise() \n", this, mNativeWindowId );
 }
@@ -192,12 +187,7 @@ void Window::Lower()
 {
   mWindowBase->Lower();
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 
   DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Lower() \n", this, mNativeWindowId );
 }
@@ -206,12 +196,7 @@ void Window::Activate()
 {
   mWindowBase->Activate();
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 
   DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Activate() \n", this, mNativeWindowId );
 }
@@ -425,12 +410,7 @@ void Window::Show()
     mVisibilityChangedSignal.Emit( handle, true );
   }
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 
   DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Show(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
 }
@@ -450,14 +430,6 @@ void Window::Hide()
     mVisibilityChangedSignal.Emit( handle, false );
   }
 
-
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
-
   DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Hide(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
 }
 
@@ -506,13 +478,6 @@ void Window::SetInputRegion( const Rect< int >& inputRegion )
 {
   mWindowBase->SetInputRegion( inputRegion );
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
-
   DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::SetInputRegion: x = %d, y = %d, w = %d, h = %d\n", inputRegion.x, inputRegion.y, inputRegion.width, inputRegion.height );
 }
 
@@ -624,12 +589,7 @@ void Window::SetSize( Dali::Window::WindowSize size )
     mAdaptor->SurfaceResizeComplete( mSurface.get(), newSize );
   }
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 }
 
 Dali::Window::WindowSize Window::GetSize() const
@@ -651,12 +611,7 @@ void Window::SetPosition( Dali::Window::WindowPosition position )
 
   mWindowSurface->MoveResize( PositionSize( position.GetX(), position.GetY(), oldRect.width, oldRect.height ) );
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 }
 
 Dali::Window::WindowPosition Window::GetPosition() const
@@ -695,12 +650,7 @@ void Window::SetPositionSize( PositionSize positionSize )
     mAdaptor->SurfaceResizeComplete( mSurface.get(), newSize );
   }
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 }
 
 Dali::Layer Window::GetRootLayer() const
@@ -766,12 +716,7 @@ void Window::OnIconifyChanged( bool iconified )
     DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Deiconified: visible = %d\n", this, mNativeWindowId, mVisible );
   }
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 }
 
 void Window::OnFocusChanged( bool focusIn )
@@ -779,12 +724,7 @@ void Window::OnFocusChanged( bool focusIn )
   Dali::Window handle( this );
   mFocusChangeSignal.Emit( handle, focusIn );
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 }
 
 void Window::OnOutputTransformed()
@@ -856,13 +796,6 @@ void Window::OnPause()
   {
     mEventHandler->Pause();
   }
-
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
 }
 
 void Window::OnResume()
@@ -872,12 +805,7 @@ void Window::OnResume()
     mEventHandler->Resume();
   }
 
-  GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
-  EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
-  if (eglGraphics)
-  {
-    eglGraphics->SetFullSwapNextFrame();
-  }
+  mSurface->SetFullSwapNextFrame();
 }
 
 void Window::RecalculateTouchPosition( Integration::Point& point )
index 7326047..021843e 100644 (file)
@@ -45,11 +45,42 @@ namespace
 {
 
 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
+const float FULL_UPDATE_RATIO( 0.8f );   ///< Force full update when the dirty area is larget than this ratio
 
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
 #endif
 
+void MergeRects( Rect< int >& mergingRect, const std::vector< Rect< int > >& rects )
+{
+  uint32_t i = 0;
+  if( mergingRect.IsEmpty() )
+  {
+    for( ; i < rects.size(); i++ )
+    {
+      if( !rects[i].IsEmpty() )
+      {
+        mergingRect = rects[i];
+        break;
+      }
+    }
+  }
+
+  for( ; i < rects.size(); i++ )
+  {
+    mergingRect.Merge( rects[i] );
+  }
+}
+
+void InsertRects( WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const std::vector< Rect< int > >& damagedRects )
+{
+  damagedRectsList.push_front( damagedRects );
+  if( damagedRectsList.size() > 4 ) // past triple buffers + current
+  {
+    damagedRectsList.pop_back();
+  }
+}
+
 } // unnamed namespace
 
 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
@@ -67,16 +98,17 @@ WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any s
   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
   mOutputTransformedSignal(),
   mFrameCallbackInfoContainer(),
+  mBufferDamagedRects(),
   mMutex(),
   mRotationAngle( 0 ),
   mScreenRotationAngle( 0 ),
+  mDpiHorizontal( 0 ),
+  mDpiVertical( 0 ),
   mOwnSurface( false ),
   mRotationSupported( false ),
   mRotationFinished( true ),
   mScreenRotationFinished( true ),
-  mResizeFinished( true ),
-  mDpiHorizontal( 0 ),
-  mDpiVertical( 0 )
+  mResizeFinished( true )
 {
   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
   Initialize( surface );
@@ -423,8 +455,6 @@ bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rec
 
   MakeContextCurrent();
 
-  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
-
   if( resizingSurface )
   {
     // Window rotate or screen rotate
@@ -456,18 +486,10 @@ bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rec
       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
     }
 
-    if (eglGraphics)
-    {
-      Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
-      eglImpl.SetFullSwapNextFrame();
-    }
+    SetFullSwapNextFrame();
   }
 
-  if (eglGraphics)
-  {
-    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
-    eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
-  }
+  SetBufferDamagedRects( damagedRects, clippingRect );
 
   return true;
 }
@@ -511,8 +533,7 @@ void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, b
       }
     }
 
-    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
-    eglImpl.SwapBuffers( mEGLSurface, damagedRects );
+    SwapBuffers( damagedRects );
 
     if( mRenderNotification )
     {
@@ -646,6 +667,132 @@ void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor
   }
 }
 
+void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
+{
+  auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
+  if ( eglGraphics )
+  {
+    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+    if( !eglImpl.IsPartialUpdateRequired() )
+    {
+      return;
+    }
+
+    Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
+
+    if( mFullSwapNextFrame )
+    {
+      InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
+      clippingRect = Rect< int >();
+      return;
+    }
+
+    EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
+
+    // Buffer age 0 means the back buffer in invalid and requires full swap
+    if( !damagedRects.size() || bufferAge == 0 )
+    {
+      InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
+      clippingRect = Rect< int >();
+      return;
+    }
+
+    // We push current frame damaged rects here, zero index for current frame
+    InsertRects( mBufferDamagedRects, damagedRects );
+
+    // Merge damaged rects into clipping rect
+    auto bufferDamagedRects = mBufferDamagedRects.begin();
+    while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
+    {
+      const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
+      MergeRects( clippingRect, rects );
+    }
+
+    if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
+    {
+      // clipping area too big or doesn't intersect surface rect
+      clippingRect = Rect< int >();
+      return;
+    }
+
+    std::vector< Rect< int > > damagedRegion;
+    damagedRegion.push_back( clippingRect );
+
+    eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
+  }
+}
+
+void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
+{
+  auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
+  if( eglGraphics )
+  {
+    Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
+
+    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+    if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
+    {
+      mFullSwapNextFrame = false;
+      eglImpl.SwapBuffers( mEGLSurface );
+      return;
+    }
+
+    mFullSwapNextFrame = false;
+
+    std::vector< Rect< int > > mergedRects = damagedRects;
+
+    // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
+    // Could be optional and can be removed, needs to be checked with and without on platform
+    const int n = mergedRects.size();
+    for( int i = 0; i < n - 1; i++ )
+    {
+      if( mergedRects[i].IsEmpty() )
+      {
+        continue;
+      }
+
+      for( int j = i + 1; j < n; j++ )
+      {
+        if( mergedRects[j].IsEmpty() )
+        {
+          continue;
+        }
+
+        if( mergedRects[i].Intersects( mergedRects[j] ) )
+        {
+          mergedRects[i].Merge( mergedRects[j] );
+          mergedRects[j].width = 0;
+          mergedRects[j].height = 0;
+        }
+      }
+    }
+
+    int j = 0;
+    for( int i = 0; i < n; i++ )
+    {
+      if( !mergedRects[i].IsEmpty() )
+      {
+        mergedRects[j++] = mergedRects[i];
+      }
+    }
+
+    if( j != 0 )
+    {
+      mergedRects.resize( j );
+    }
+
+    if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
+    {
+      eglImpl.SwapBuffers( mEGLSurface );
+    }
+    else
+    {
+      eglImpl.SwapBuffers( mEGLSurface, mergedRects );
+    }
+  }
+}
+
 } // namespace Adaptor
 
 } // namespace internal
index 6b72a55..faf8f50 100644 (file)
@@ -51,7 +51,8 @@ class WindowRenderSurface : public Dali::RenderSurfaceInterface, public Connecti
 {
 public:
 
-  typedef Signal< void ( ) > OutputSignalType;
+  using OutputSignalType = Signal< void ( ) >;
+  using DamagedRectsContainer = std::list< std::vector< Rect< int > > >;
 
   /**
     * Uses an window surface to render to.
@@ -231,6 +232,19 @@ private:
    */
   void OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor );
 
+  /**
+   * @brief Set the buffer damage rects.
+   * @param[in] damagedRects List of damaged rects
+   * @param[in] clippingRect The rect to clip rendered scene
+   */
+  void SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect );
+
+  /**
+   * @brief Swap buffers.
+   * @param[in] damagedRects List of damaged rects
+   */
+  void SwapBuffers( const std::vector<Rect<int>>& damagedRects );
+
 protected:
 
   // Undefined
@@ -285,18 +299,18 @@ private: // Data
   ColorDepth                      mColorDepth;         ///< Color depth of surface (32 bit or 24 bit)
   OutputSignalType                mOutputTransformedSignal;
   FrameCallbackInfoContainer      mFrameCallbackInfoContainer;
+  DamagedRectsContainer           mBufferDamagedRects;
   Dali::Mutex                     mMutex;
   int                             mRotationAngle;
   int                             mScreenRotationAngle;
+  uint32_t                        mDpiHorizontal;
+  uint32_t                        mDpiVertical;
   bool                            mOwnSurface;         ///< Whether we own the surface (responsible for deleting it)
   bool                            mRotationSupported;
   bool                            mRotationFinished;
   bool                            mScreenRotationFinished;
   bool                            mResizeFinished;
 
-  uint32_t                        mDpiHorizontal;
-  uint32_t                        mDpiVertical;
-
 }; // class WindowRenderSurface
 
 } // namespace Adaptor
index 7ade18f..2aaa623 100644 (file)
@@ -226,18 +226,7 @@ void NativeRenderSurfaceEcoreWl::StartRender()
 
 bool NativeRenderSurfaceEcoreWl::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
 {
-  auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics*>(mGraphics);
-  if (eglGraphics)
-  {
-    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
-    if (resizingSurface)
-    {
-      eglImpl.SetFullSwapNextFrame();
-    }
-
-    eglImpl.SetDamage(mEGLSurface, damagedRects, clippingRect);
-  }
-
+  //TODO: Need to support partial update
   return true;
 }