uint32_t surfaceHeight,
uint32_t horizontalDpi,
uint32_t verticalDpi,
- bool initialize )
+ bool initialize,
+ bool enablePartialUpdate )
: mCore( NULL ),
mSurfaceWidth( surfaceWidth ),
mSurfaceHeight( surfaceHeight ),
mFrame( 0u ),
mDpi{ horizontalDpi, verticalDpi },
- mLastVSyncTime(0u)
+ mLastVSyncTime(0u),
+ mPartialUpdateEnabled(enablePartialUpdate)
{
if( initialize )
{
mGlContextHelperAbstraction,
Integration::RenderToFrameBuffer::FALSE,
Integration::DepthBufferAvailable::TRUE,
- Integration::StencilBufferAvailable::TRUE );
+ Integration::StencilBufferAvailable::TRUE,
+ mPartialUpdateEnabled ? Integration::PartialUpdateAvailable::TRUE : Integration::PartialUpdateAvailable::FALSE );
mCore->ContextCreated();
mRenderStatus.SetNeedsPostRender( false );
mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ );
- mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/);
- mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/);
+ mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/ );
+ mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/ );
mCore->PostRender( false /*do not skip rendering*/ );
mFrame++;
return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
}
+bool TestApplication::PreRenderWithPartialUpdate(uint32_t intervalMilliseconds, const char* location, std::vector<Rect<int>>& damagedRects)
+{
+ DoUpdate(intervalMilliseconds, location);
+
+ mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ );
+ mCore->PreRender(mScene, damagedRects);
+
+ return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
+}
+
+bool TestApplication::RenderWithPartialUpdate(std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
+{
+ mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/, clippingRect);
+ mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/, clippingRect);
+ mCore->PostRender(false /*do not skip rendering*/);
+
+ mFrame++;
+
+ return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
+}
+
uint32_t TestApplication::GetUpdateStatus()
{
return mStatus.KeepUpdating();
{
// Update Time values
mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ );
- mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/);
- mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/);
+ mCore->RenderScene( mRenderStatus, mScene, true /*render the off-screen buffers*/ );
+ mCore->RenderScene( mRenderStatus, mScene, false /*render the surface*/ );
mCore->PostRender( false /*do not skip rendering*/ );
mFrame++;
uint32_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
uint32_t horizontalDpi = DEFAULT_HORIZONTAL_DPI,
uint32_t verticalDpi = DEFAULT_VERTICAL_DPI,
- bool initialize = true );
+ bool initialize = true,
+ bool enablePartialUpdate = false );
void Initialize();
void CreateCore();
void ProcessEvent(const Integration::Event& event);
void SendNotification();
bool Render( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL, const char* location=NULL );
+ bool PreRenderWithPartialUpdate(uint32_t intervalMilliseconds, const char* location, std::vector<Rect<int>>& damagedRects);
+ bool RenderWithPartialUpdate(std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect);
uint32_t GetUpdateStatus();
bool UpdateOnly( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL );
bool RenderOnly( );
struct { uint32_t x; uint32_t y; } mDpi;
uint32_t mLastVSyncTime;
+ bool mPartialUpdateEnabled;
static bool mLoggingEnabled;
};
*/
#include <dali/dali.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/internal/system/linux/dali-ecore-x.h>
#include <dali-test-suite-utils.h>
END_TEST;
}
+
+int UtcDaliWindowPartialUpdate(void)
+{
+ Dali::Window window;
+ try
+ {
+ std::vector<Rect<int>> damagedAreas;
+ DevelWindow::SetDamagedAreas(window, damagedAreas);
+ DALI_TEST_CHECK( false ); // Should not reach here!
+ }
+ catch( ... )
+ {
+ DALI_TEST_CHECK( true );
+ }
+
+ END_TEST;
+}
return GetImplementation( window ).GetNativeId();
}
+void SetDamagedAreas(Window window, std::vector<Dali::Rect<int>>& areas)
+{
+ GetImplementation(window).SetDamagedAreas(areas);
+}
+
} // namespace DevelWindow
} // namespace Dali
#define DALI_WINDOW_DEVEL_H
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
*/
+// EXTERNAL INCLUDES
+
// INTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
#include <dali/public-api/adaptor-framework/window.h>
namespace Dali
*/
DALI_ADAPTOR_API int32_t GetNativeId( Window window );
+/**
+ * @brief Sets damaged areas of the window.
+ *
+ * This API is for setting static damaged areas of the window for partial update.
+ *
+ * @param[in] window The window instance
+ * @param[in] areas The damaged areas list to set
+ */
+DALI_ADAPTOR_API void SetDamagedAreas(Window window, std::vector<Dali::Rect<int>>& areas);
+
} // namespace DevelWindow
} // namespace Dali
// EXTERNAL INCLUDES
#include <dali/integration-api/core-enumerations.h>
+#include <dali/public-api/common/vector-wrapper.h>
#include <dali/public-api/math/vector4.h>
#include <dali/public-api/math/rect.h>
#include <dali/public-api/object/any.h>
* If the operation fails, then Core::Render should not be called until there is
* a surface to render onto.
* @param[in] resizingSurface True if the surface is being resized
+ * @param[in] damagedRects List of damaged rects this render pass
* @return True if the operation is successful, False if the operation failed
*/
- virtual bool PreRender( bool resizingSurface ) = 0;
+ virtual bool PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect ) = 0;
/**
* @brief Invoked by render thread after Core::Render
* @param[in] replacingSurface True if the surface is being replaced.
* @param[in] resizingSurface True if the surface is being resized.
*/
- virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface ) = 0;
+ virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) = 0;
+
/**
* @brief Invoked by render thread when the thread should be stop
*/
// INTERNAL INCLUDES
#include <dali/internal/adaptor/common/adaptor-impl.h>
#include <dali/internal/adaptor/common/lifecycle-observer.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
#include <dali/internal/input/common/key-impl.h>
#include <dali/internal/input/common/physical-keyboard-impl.h>
{
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();
+ }
}
Dali::RenderSurfaceInterface* SceneHolder::GetSurface() const
if( mScene )
{
mScene.SetBackgroundColor( color );
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
}
}
eglContextHelperImpl,
( 0u != mEnvironmentOptions->GetRenderToFboInterval() ) ? Integration::RenderToFrameBuffer::TRUE : Integration::RenderToFrameBuffer::FALSE,
mGraphics->GetDepthBufferRequired(),
- mGraphics->GetStencilBufferRequired() );
+ mGraphics->GetStencilBufferRequired(),
+ mGraphics->GetPartialUpdateRequired() );
defaultWindow->SetAdaptor( Get() );
windowSurface->InitializeGraphics();
+ // clear previous frame damaged render items rects, buffer history is tracked on surface level
+ mDamagedRects.clear();
+
+ // If user damaged areas are not set
+ if (!eglImpl.DamageAreasSet())
+ {
+ // Collect damage rects
+ mCore.PreRender( scene, mDamagedRects );
+ }
+
// Render off-screen frame buffers first if any
mCore.RenderScene( windowRenderStatus, scene, true );
- // Switch to the EGL context of the surface
- windowSurface->PreRender( surfaceResized ); // Switch GL context
+ 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
+
+ if (clippingRect.IsEmpty())
+ {
+ mDamagedRects.clear();
+ }
// Render the surface
- mCore.RenderScene( windowRenderStatus, scene, false );
+ mCore.RenderScene( windowRenderStatus, scene, false, clippingRect );
if( windowRenderStatus.NeedsPostRender() )
{
- windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer
+ windowSurface->PostRender( false, false, surfaceResized, mDamagedRects ); // Swap Buffer with damage
}
}
}
volatile unsigned int mUploadWithoutRendering; ///< Will be set to upload the resource only (with no rendering)
volatile unsigned int mFirstFrameAfterResume; ///< Will be set to check the first frame after resume (for log)
+
+ std::vector<Rect<int>> mDamagedRects; ///< Keeps collected damaged render items rects for one render pass
};
} // namespace Adaptor
* Constructor
*/
GraphicsInterface()
-: mDepthBufferRequired( Integration::DepthBufferAvailable::FALSE ),
- mStencilBufferRequired( Integration::StencilBufferAvailable::FALSE )
+ : mDepthBufferRequired( Integration::DepthBufferAvailable::FALSE ),
+ mStencilBufferRequired( Integration::StencilBufferAvailable::FALSE ),
+ mPartialUpdateRequired( Integration::PartialUpdateAvailable::FALSE )
{
};
return mStencilBufferRequired;
};
+ /**
+ * Get whether the stencil buffer is required
+ * @return TRUE if the stencil buffer is required
+ */
+ Integration::PartialUpdateAvailable GetPartialUpdateRequired()
+ {
+ return mPartialUpdateRequired;
+ };
protected:
Integration::DepthBufferAvailable mDepthBufferRequired; ///< Whether the depth buffer is required
Integration::StencilBufferAvailable mStencilBufferRequired; ///< Whether the stencil buffer is required
+ Integration::PartialUpdateAvailable mPartialUpdateRequired; ///< Whether the partial update is required
};
} // Adaptor
mDepthBufferRequired = static_cast< Integration::DepthBufferAvailable >( environmentOptions->DepthBufferRequired() );
mStencilBufferRequired = static_cast< Integration::StencilBufferAvailable >( environmentOptions->StencilBufferRequired() );
+ mPartialUpdateRequired = static_cast< Integration::PartialUpdateAvailable >( environmentOptions->PartialUpdateRequired() );
mMultiSamplingLevel = environmentOptions->GetMultiSamplingLevel();
EglInterface* EglGraphics::Create()
{
- mEglImplementation = Utils::MakeUnique< EglImplementation >( mMultiSamplingLevel, mDepthBufferRequired, mStencilBufferRequired );
+ mEglImplementation = Utils::MakeUnique< EglImplementation >( mMultiSamplingLevel, mDepthBufferRequired, mStencilBufferRequired, mPartialUpdateRequired );
mEglImageExtensions = Utils::MakeUnique< EglImageExtensions >( mEglImplementation.get() );
mEglSync->Initialize( mEglImplementation.get() ); // The sync impl needs the EglDisplay
return mEglImageExtensions.get();
}
+void EglGraphics::SetDamagedAreas(std::vector<Dali::Rect<int>>& areas)
+{
+ mEglImplementation->SetDamageAreas(areas);
+}
+
+void EglGraphics::SetFullSwapNextFrame()
+{
+ mEglImplementation->SetFullSwapNextFrame();
+}
+
} // Adaptor
} // Internal
} // Dali
EglImageExtensions* GetImageExtensions();
/**
+ * Sets fixed damaged areas for partial rendering. This overrides automatic partial rendering.
+ */
+ void SetDamagedAreas( std::vector<Dali::Rect<int>>& areas );
+
+ /**
+ * 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;
EglImplementation::EglImplementation( int multiSamplingLevel,
Integration::DepthBufferAvailable depthBufferRequired,
- Integration::StencilBufferAvailable stencilBufferRequired )
+ Integration::StencilBufferAvailable stencilBufferRequired ,
+ Integration::PartialUpdateAvailable partialUpdateRequired )
: mContextAttribs(),
mEglNativeDisplay( 0 ),
mEglNativeWindow( 0 ),
mIsWindow( true ),
mDepthBufferRequired( depthBufferRequired == Integration::DepthBufferAvailable::TRUE ),
mStencilBufferRequired( stencilBufferRequired == Integration::StencilBufferAvailable::TRUE ),
+ mPartialUpdateRequired( partialUpdateRequired == Integration::PartialUpdateAvailable::TRUE ),
mIsSurfacelessContextSupported( false ),
mIsKhrCreateContextSupported( false ),
- mSwapBufferCountAfterResume( 0 )
+ mSwapBufferCountAfterResume( 0 ),
+ mEglSetDamageRegionKHR( 0 ),
+ mEglSwapBuffersWithDamageKHR( 0 ),
+ mBufferAge( 0 ),
+ mFullSwapNextFrame( true )
{
}
DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
+ mEglSetDamageRegionKHR = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
+ if (!mEglSetDamageRegionKHR)
+ {
+ DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n");
+ mPartialUpdateRequired = false;
+ }
+ mEglSwapBuffersWithDamageKHR = reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
+ if (!mEglSwapBuffersWithDamageKHR)
+ {
+ DALI_LOG_ERROR("Coudn't find eglSwapBuffersWithDamageKHR!\n");
+ mPartialUpdateRequired = false;
+ }
return true;
}
mEglWindowContexts.push_back( eglContext );
+ mEglSetDamageRegionKHR = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
+ if (!mEglSetDamageRegionKHR)
+ {
+ DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n");
+ mPartialUpdateRequired = false;
+ }
+ mEglSwapBuffersWithDamageKHR = reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
+ if (!mEglSwapBuffersWithDamageKHR)
+ {
+ DALI_LOG_ERROR("Coudn't find eglSwapBuffersWithDamageKHR!\n");
+ mPartialUpdateRequired = false;
+ }
return true;
}
}
#endif //DALI_PROFILE_UBUNTU
+ // DALI_LOG_ERROR("EglImplementation::SwapBuffers()\n");
eglSwapBuffers( mEglDisplay, eglSurface );
+ mFullSwapNextFrame = false;
+
+#ifndef DALI_PROFILE_UBUNTU
+ if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
+ {
+ DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
+ mSwapBufferCountAfterResume++;
+ }
+#endif //DALI_PROFILE_UBUNTU
+ }
+}
+
+EGLint EglImplementation::GetBufferAge(EGLSurface& eglSurface) const
+{
+ EGLint age = 0;
+ eglQuerySurface(mEglDisplay, eglSurface, EGL_BUFFER_AGE_EXT, &age);
+ if (age < 0)
+ {
+ DALI_LOG_ERROR("eglQuerySurface(%d)\n", eglGetError());
+ age = 0;
+ }
+
+ // 0 - invalid buffer
+ // 1, 2, 3
+ if (age > 3)
+ {
+ DALI_LOG_ERROR("EglImplementation::GetBufferAge() buffer age %d > 3\n", age);
+ age = 0; // shoudn't be more than 3 back buffers, if there is just reset, I don't want to add extra history level
+ }
+
+ return age;
+}
+
+bool EglImplementation::DamageAreasSet() const
+{
+ return (mDamagedAreas.size() ? true : false);
+}
+
+void EglImplementation::SetDamageAreas( std::vector<Dali::Rect<int>>& damagedAreas )
+{
+ mFullSwapNextFrame = true;
+ mDamagedAreas = damagedAreas;
+}
+
+void EglImplementation::SetFullSwapNextFrame()
+{
+ 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)
+ {
+ return;
+ }
+
+ 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)
+ {
+ mBufferAge = 0;
+ insertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
+ clippingRect = Rect<int>();
+ return;
+ }
+
+ EGLint bufferAge = GetBufferAge(eglSurface);
+ if (mDamagedAreas.size())
+ {
+ mBufferAge = bufferAge;
+ if (bufferAge == 0)
+ {
+ // Buffer age is reset
+ clippingRect = Rect<int>();
+ return;
+ }
+
+ mergeRects(clippingRect, mDamagedAreas);
+ }
+ else
+ {
+ // Buffer age 0 means the back buffer in invalid and requires full swap
+ if (!damagedRects.size() || bufferAge != mBufferAge || bufferAge == 0)
+ {
+ // No damage or buffer is out of order or buffer age is reset
+ mBufferAge = bufferAge;
+ insertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
+ clippingRect = Rect<int>();
+ return;
+ }
+
+ // We push current frame damaged rects here, zero index for current frame
+ mBufferAge = bufferAge;
+ 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);
+ if (result == EGL_FALSE)
+ {
+ DALI_LOG_ERROR("eglSetDamageRegionKHR(%d)\n", eglGetError());
+ }
+ }
+}
+
+void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects)
+{
+ if (eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
+ {
+ if (!mPartialUpdateRequired || mFullSwapNextFrame || mBufferAge == 0 || !damagedRects.size())
+ {
+ SwapBuffers(eglSurface);
+ return;
+ }
+
+#ifndef DALI_PROFILE_UBUNTU
+ if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
+ {
+ DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" );
+ }
+#endif //DALI_PROFILE_UBUNTU
+
+ if (mDamagedAreas.size())
+ {
+ // DALI_LOG_ERROR("EglImplementation::SwapBuffers(%d)\n", mDamagedAreas.size());
+ EGLBoolean result = mEglSwapBuffersWithDamageKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(mDamagedAreas.data()), mDamagedAreas.size());
+ if (result == EGL_FALSE)
+ {
+ DALI_LOG_ERROR("eglSwapBuffersWithDamageKHR(%d)\n", eglGetError());
+ }
+
+#ifndef DALI_PROFILE_UBUNTU
+ if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
+ {
+ DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
+ mSwapBufferCountAfterResume++;
+ }
+#endif //DALI_PROFILE_UBUNTU
+ return;
+ }
+
+ // current frame damaged rects were pushed by EglImplementation::SetDamage() to 0 index.
+ EGLint bufferAge = mBufferAge;
+ mCombinedDamagedRects.clear();
+
+ // Combine damaged rects from previous frames (beginning from bufferAge index) with the current frame (0 index)
+ auto bufferDamagedRects = mBufferDamagedRects.begin();
+ while (bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
+ {
+ const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
+ mCombinedDamagedRects.insert(mCombinedDamagedRects.end(), rects.begin(), rects.end());
+ }
+
+ // 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 = mCombinedDamagedRects.size();
+ for (int i = 0; i < n-1; i++)
+ {
+ if (mCombinedDamagedRects[i].IsEmpty())
+ {
+ continue;
+ }
+
+ for (int j = i+1; j < n; j++)
+ {
+ if (mCombinedDamagedRects[j].IsEmpty())
+ {
+ continue;
+ }
+
+ if (mCombinedDamagedRects[i].Intersects(mCombinedDamagedRects[j]))
+ {
+ mCombinedDamagedRects[i].Merge(mCombinedDamagedRects[j]);
+ mCombinedDamagedRects[j].width = 0;
+ mCombinedDamagedRects[j].height = 0;
+ }
+ }
+ }
+
+ int j = 0;
+ for (int i = 0; i < n; i++)
+ {
+ if (!mCombinedDamagedRects[i].IsEmpty())
+ {
+ mCombinedDamagedRects[j++] = mCombinedDamagedRects[i];
+ }
+ }
+
+ if (j != 0)
+ {
+ mCombinedDamagedRects.resize(j);
+ }
+
+ if (!mCombinedDamagedRects.size() || (mCombinedDamagedRects[0].Area() > mSurfaceRect.Area() * 0.8))
+ {
+ SwapBuffers(eglSurface);
+ return;
+ }
+
+ // DALI_LOG_ERROR("EglImplementation::SwapBuffers(%d)\n", mCombinedDamagedRects.size());
+ EGLBoolean result = mEglSwapBuffersWithDamageKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(mCombinedDamagedRects.data()), mCombinedDamagedRects.size());
+ if (result == EGL_FALSE)
+ {
+ DALI_LOG_ERROR("eglSwapBuffersWithDamageKHR(%d)\n", eglGetError());
+ }
#ifndef DALI_PROFILE_UBUNTU
if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
*/
// EXTERNAL INCLUDES
+#include <dali/public-api/common/list-wrapper.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
#include <dali/internal/graphics/common/egl-include.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/rect.h>
#include <dali/integration-api/core-enumerations.h>
// INTERNAL INCLUDES
* @param[in] multiSamplingLevel The Multi-sampling level required
* @param[in] depthBufferRequired Whether the depth buffer is required
* @param[in] stencilBufferRequired Whether the stencil buffer is required
+ * @param[in] partialUpdatedRequired Whether the partial update is required
*/
EglImplementation( int multiSamplingLevel,
Integration::DepthBufferAvailable depthBufferRequired,
- Integration::StencilBufferAvailable stencilBufferRequired );
+ Integration::StencilBufferAvailable stencilBufferRequired,
+ Integration::PartialUpdateAvailable partialUpdateRequired );
/**
* Destructor
virtual void SwapBuffers( EGLSurface& eglSurface );
/**
+ * Gets current back buffer age
+ */
+ EGLint GetBufferAge( EGLSurface& eglSurface ) const;
+
+ /**
+ * Gets if user set damaged areas
+ */
+ bool DamageAreasSet() const;
+
+ /**
+ * Sets damaged areas, overrides auto calculated ones
+ */
+ void SetDamageAreas( std::vector<Dali::Rect<int>>& damagedArea );
+
+ /**
+ * 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 );
+
+ /**
+ * Performs an OpenGL swap buffers command with damaged rects
+ */
+ virtual void SwapBuffers( EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects );
+
+ /**
* Performs an OpenGL copy buffers command
*/
virtual void CopyBuffers( EGLSurface& eglSurface );
bool mIsWindow;
bool mDepthBufferRequired;
bool mStencilBufferRequired;
+ bool mPartialUpdateRequired;
bool mIsSurfacelessContextSupported;
bool mIsKhrCreateContextSupported;
uint32_t mSwapBufferCountAfterResume;
+ PFNEGLSETDAMAGEREGIONKHRPROC mEglSetDamageRegionKHR;
+ PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC mEglSwapBuffersWithDamageKHR;
+
+ EGLint mBufferAge;
+ std::list<std::vector<Rect<int>>> mBufferDamagedRects;
+ std::vector<Rect<int>> mCombinedDamagedRects;
+ std::vector<Rect<int>> mDamagedAreas;
+ Rect<int> mSurfaceRect;
+ bool mFullSwapNextFrame;
};
} // namespace Adaptor
const int DEFAULT_MULTI_SAMPLING_LEVEL = -1;
const bool DEFAULT_DEPTH_BUFFER_REQUIRED_SETTING = true;
const bool DEFAULT_STENCIL_BUFFER_REQUIRED_SETTING = true;
+const bool DEFAULT_PARTIAL_UPDATE_REQUIRED_SETTING = false;
unsigned int GetIntegerEnvironmentVariable( const char* variable, unsigned int defaultValue )
{
mThreadingMode( ThreadingMode::COMBINED_UPDATE_RENDER ),
mGlesCallAccumulate( false ),
mDepthBufferRequired( DEFAULT_DEPTH_BUFFER_REQUIRED_SETTING ),
- mStencilBufferRequired( DEFAULT_STENCIL_BUFFER_REQUIRED_SETTING )
+ mStencilBufferRequired( DEFAULT_STENCIL_BUFFER_REQUIRED_SETTING ),
+ mPartialUpdateRequired( DEFAULT_PARTIAL_UPDATE_REQUIRED_SETTING )
{
ParseEnvironmentOptions();
}
return mStencilBufferRequired;
}
+bool EnvironmentOptions::PartialUpdateRequired() const
+{
+ return mPartialUpdateRequired;
+}
+
void EnvironmentOptions::ParseEnvironmentOptions()
{
// get logging options
mStencilBufferRequired = false;
}
}
+
+ int partialUpdateRequired( -1 );
+ if( GetIntegerEnvironmentVariable( DALI_ENV_ENABLE_PARTIAL_UPDATE, partialUpdateRequired ) )
+ {
+ if( partialUpdateRequired > 0 )
+ {
+ mPartialUpdateRequired = true;
+ }
+ }
}
} // Adaptor
*/
bool StencilBufferRequired() const;
+ /**
+ * @return Whether the partial update is required.
+ */
+ bool PartialUpdateRequired() const;
+
/// Deleted copy constructor.
EnvironmentOptions( const EnvironmentOptions& ) = delete;
bool mGlesCallAccumulate; ///< Whether or not to accumulate gles call statistics
bool mDepthBufferRequired; ///< Whether the depth buffer is required
bool mStencilBufferRequired; ///< Whether the stencil buffer is required
+ bool mPartialUpdateRequired; ///< Whether the partial update is required
std::unique_ptr<TraceManager> mTraceManager; ///< TraceManager
};
#define DALI_ENV_DISABLE_STENCIL_BUFFER "DALI_DISABLE_STENCIL_BUFFER"
+#define DALI_ENV_ENABLE_PARTIAL_UPDATE "DALI_ENABLE_PARTIAL_UPDATE"
+
#define DALI_ENV_WEB_ENGINE_NAME "DALI_WEB_ENGINE_NAME"
#define DALI_ENV_DPI_HORIZONTAL "DALI_DPI_HORIZONTAL"
// INTERNAL HEADERS
#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
#include <dali/internal/window-system/common/event-handler.h>
#include <dali/internal/window-system/common/orientation-impl.h>
#include <dali/internal/window-system/common/render-surface-factory.h>
void Window::Raise()
{
mWindowBase->Raise();
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
+
DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Raise() \n", this, mNativeWindowId );
}
void Window::Lower()
{
mWindowBase->Lower();
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
+
DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Lower() \n", this, mNativeWindowId );
}
void Window::Activate()
{
mWindowBase->Activate();
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
+
DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Activate() \n", this, mNativeWindowId );
}
mVisibilityChangedSignal.Emit( handle, true );
}
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
+
DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Show(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
}
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 );
}
{
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 );
}
mAdaptor->SurfaceResizeComplete( mSurface.get(), newSize );
}
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
}
Dali::Window::WindowSize Window::GetSize() const
PositionSize oldRect = mSurface->GetPositionSize();
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();
+ }
}
Dali::Window::WindowPosition Window::GetPosition() const
mResizeSignal.Emit( handle, newSize );
mAdaptor->SurfaceResizeComplete( mSurface.get(), newSize );
}
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
}
Dali::Layer Window::GetRootLayer() const
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();
+ }
}
void Window::OnFocusChanged( bool focusIn )
Dali::Window handle( this );
mFocusChangedSignal.Emit( focusIn );
mFocusChangeSignal.Emit( handle, focusIn );
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
}
void Window::OnOutputTransformed()
{
mEventHandler->Pause();
}
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
}
void Window::OnResume()
{
mEventHandler->Resume();
}
+
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetFullSwapNextFrame();
+ }
}
void Window::RecalculateTouchPosition( Integration::Point& point )
return mWindowBase->GetNativeWindowId();
}
+void Window::SetDamagedAreas(std::vector<Dali::Rect<int>>& areas)
+{
+ GraphicsInterface& graphics = mAdaptor->GetGraphicsInterface();
+ EglGraphics* eglGraphics = static_cast<EglGraphics*>(&graphics);
+ if (eglGraphics)
+ {
+ eglGraphics->SetDamagedAreas(areas);
+ }
+}
+
} // Adaptor
} // Internal
*/
void SetAvailableOrientations( const Dali::Vector<Dali::Window::WindowOrientation>& orientations );
+ /**
+ * @copydoc Dali::DevelWindow::SetDamagedAreas()
+ */
+ void SetDamagedAreas(std::vector<Dali::Rect<int>>& areas);
+
public: // Dali::Internal::Adaptor::SceneHolder
/**
{
}
-bool WindowRenderSurface::PreRender( bool resizingSurface )
+bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
{
MakeContextCurrent();
+ auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
if( resizingSurface )
{
// Window rotate or screen rotate
DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
}
+
+ if (eglGraphics)
+ {
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+ eglImpl.SetFullSwapNextFrame();
+ }
}
- auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
- if ( eglGraphics )
+ if (eglGraphics)
{
- GlImplementation& mGLES = eglGraphics->GetGlesInterface();
- mGLES.PreRender();
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+ eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
}
return true;
}
-void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
+void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
{
// Inform the gl implementation that rendering has finished before informing the surface
auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
}
Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
- eglImpl.SwapBuffers( mEGLSurface );
+ eglImpl.SwapBuffers( mEGLSurface, damagedRects );
if( mRenderNotification )
{
/**
* @copydoc Dali::RenderSurfaceInterface::PreRender()
*/
- virtual bool PreRender( bool resizingSurface ) override;
+ virtual bool PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect ) override;
/**
* @copydoc Dali::RenderSurfaceInterface::PostRender()
*/
- virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface );
+ virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) override;
/**
* @copydoc Dali::RenderSurfaceInterface::StopRender()
{
}
-bool NativeRenderSurfaceEcoreWl::PreRender( bool )
+bool NativeRenderSurfaceEcoreWl::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
{
- // nothing to do for pixmaps
+ 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);
+ }
+
return true;
}
-void NativeRenderSurfaceEcoreWl::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
+void NativeRenderSurfaceEcoreWl::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
{
auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
- if ( eglGraphics )
+ if (eglGraphics)
{
Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
-
- eglImpl.SwapBuffers( mEGLSurface );
+ eglImpl.SwapBuffers( mEGLSurface, damagedRects );
}
if( mThreadSynchronization )
/**
* @copydoc Dali::RenderSurfaceInterface::PreRender()
*/
- virtual bool PreRender( bool resizingSurface ) override;
+ virtual bool PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect ) override;
/**
* @copydoc Dali::RenderSurfaceInterface::PostRender()
*/
- virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface );
+ virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) override;
/**
* @copydoc Dali::RenderSurfaceInterface::StopRender()
{
}
-bool PixmapRenderSurfaceEcoreX::PreRender( bool )
+bool PixmapRenderSurfaceEcoreX::PreRender( bool, const std::vector<Rect<int>>&, Rect<int>& )
{
// Nothing to do for pixmaps
return true;
}
-void PixmapRenderSurfaceEcoreX::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
+void PixmapRenderSurfaceEcoreX::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
{
auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
/**
* @copydoc Dali::RenderSurfaceInterface::PreRender()
*/
- virtual bool PreRender( bool resizingSurface ) override;
+ virtual bool PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect ) override;
/**
* @copydoc Dali::RenderSurfaceInterface::PostRender()
*/
- virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface ) override;
+ virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) override;
/**
* @copydoc Dali::RenderSurfaceInterface::StopRender()