/*
- * 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.
namespace
{
- const uint32_t CHECK_EXTENSION_NUMBER = 3;
+ const uint32_t THRESHOLD_SWAPBUFFER_COUNT = 5;
+ const uint32_t CHECK_EXTENSION_NUMBER = 2;
const std::string EGL_KHR_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context";
const std::string EGL_KHR_CREATE_CONTEXT = "EGL_KHR_create_context";
- const std::string EGL_KHR_PARTIAL_UPDATE = "EGL_KHR_partial_update";
}
namespace Dali
EglImplementation::EglImplementation( int multiSamplingLevel,
Integration::DepthBufferAvailable depthBufferRequired,
- Integration::StencilBufferAvailable stencilBufferRequired,
- Integration::PartialUpdateAvailable partialUpdateAvailable )
+ Integration::StencilBufferAvailable stencilBufferRequired ,
+ Integration::PartialUpdateAvailable partialUpdateRequired )
: mContextAttribs(),
mEglNativeDisplay( 0 ),
mEglNativeWindow( 0 ),
mCurrentEglContext( EGL_NO_CONTEXT ),
mMultiSamplingLevel( multiSamplingLevel ),
mGlesVersion( 30 ),
- mDamagedRectArray( 0 ),
mColorDepth( COLOR_DEPTH_24 ),
mGlesInitialized( false ),
mIsOwnSurface( true ),
mIsWindow( true ),
mDepthBufferRequired( depthBufferRequired == Integration::DepthBufferAvailable::TRUE ),
mStencilBufferRequired( stencilBufferRequired == Integration::StencilBufferAvailable::TRUE ),
+ mPartialUpdateRequired( partialUpdateRequired == Integration::PartialUpdateAvailable::TRUE ),
mIsSurfacelessContextSupported( false ),
mIsKhrCreateContextSupported( false ),
- mIsFirstFrameAfterResume( false ),
- mIsKhrPartialUpdateSupported( false ),
- mPartialUpdateAvailable( partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE )
+ mSwapBufferCountAfterResume( 0 ),
+ mEglSetDamageRegionKHR( 0 ),
+ mEglSwapBuffersWithDamageKHR( 0 )
{
- if( mPartialUpdateAvailable )
- {
- mEglSetDamageRegionKHR = reinterpret_cast< PFNEGLSETDAMAGEREGIONKHRPROC >( eglGetProcAddress( "eglSetDamageRegionKHR" ) );
- mSwapBuffersWithDamage = reinterpret_cast< PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC >( eglGetProcAddress( "eglSwapBuffersWithDamageEXT" ) );
- if( !mEglSetDamageRegionKHR || !mSwapBuffersWithDamage )
- {
- mPartialUpdateAvailable = false;
- DALI_LOG_ERROR("Initialization of partial update failed.\n");
- }
- else
- {
- DALI_LOG_RELEASE_INFO("Initialization of partial update success!\n");
- }
- }
}
EglImplementation::~EglImplementation()
{
mEglNativeDisplay = display;
- //@todo see if we can just EGL_DEFAULT_DISPLAY instead
- mEglDisplay = eglGetDisplay(mEglNativeDisplay);
- EGLint error = eglGetError();
+ // Try to get the display connection for the native display first
+ mEglDisplay = eglGetDisplay( mEglNativeDisplay );
- if( mEglDisplay == NULL && error != EGL_SUCCESS )
+ if( mEglDisplay == EGL_NO_DISPLAY )
{
+ // If failed, try to get the default display connection
+ mEglDisplay = eglGetDisplay( EGL_DEFAULT_DISPLAY );
+ }
+
+ if( mEglDisplay == EGL_NO_DISPLAY )
+ {
+ // Still failed to get a display connection
throw Dali::DaliException( "", "OpenGL ES is not supported");
}
}
eglBindAPI(EGL_OPENGL_ES_API);
- mGlesInitialized = true;
mIsOwnSurface = isOwnSurface;
}
mIsKhrCreateContextSupported = true;
extensionCheckCount++;
}
- if( currentExtension == EGL_KHR_PARTIAL_UPDATE )
- {
- mIsKhrPartialUpdateSupported = true;
- extensionCheckCount++;
- }
}
- if( !mIsKhrPartialUpdateSupported )
- {
- mPartialUpdateAvailable = false;
- }
+ mGlesInitialized = true;
// We want to display this information all the time, so use the LogMessage directly
Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
+ " PartialUpdate %d\n"
" Vendor: %s\n"
" Version: %s\n"
" Client APIs: %s\n"
" Extensions: %s\n",
+ mPartialUpdateRequired,
eglQueryString( mEglDisplay, EGL_VENDOR ),
eglQueryString( mEglDisplay, EGL_VERSION ),
eglQueryString( mEglDisplay, EGL_CLIENT_APIS ),
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;
}
void EglImplementation::DestroyContext( EGLContext& eglContext )
{
- DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
-
- eglDestroyContext( mEglDisplay, eglContext );
- eglContext = 0;
+ if( eglContext )
+ {
+ eglDestroyContext( mEglDisplay, eglContext );
+ eglContext = 0;
+ }
}
void EglImplementation::DestroySurface( EGLSurface& eglSurface )
return mGlesInitialized;
}
-
-const char* GetEglErrorString(EGLint error)
-{
- switch(error)
- {
- case EGL_SUCCESS: return "No error";
- case EGL_NOT_INITIALIZED: return "EGL not initialized or failed to initialize";
- case EGL_BAD_ACCESS: return "Resource inaccessible";
- case EGL_BAD_ALLOC: return "Cannot allocate resources";
- case EGL_BAD_ATTRIBUTE: return "Unrecognized attribute or attribute value";
- case EGL_BAD_CONTEXT: return "Invalid EGL context";
- case EGL_BAD_CONFIG: return "Invalid EGL frame buffer configuration";
- case EGL_BAD_CURRENT_SURFACE: return "Current surface is no longer valid";
- case EGL_BAD_DISPLAY: return "Invalid EGL display";
- case EGL_BAD_SURFACE: return "Invalid surface";
- case EGL_BAD_MATCH: return "Inconsistent arguments";
- case EGL_BAD_PARAMETER: return "Invalid argument";
- case EGL_BAD_NATIVE_PIXMAP: return "Invalid native pixmap";
- case EGL_BAD_NATIVE_WINDOW: return "Invalid native window";
- case EGL_CONTEXT_LOST: return "Context lost";
- }
- return "Unknown error ";
-}
-
-
void EglImplementation::SwapBuffers( EGLSurface& eglSurface )
{
if ( eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
{
- if( mIsFirstFrameAfterResume )
- {
- DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers: First SwapBuffers call.\n" );
- mIsFirstFrameAfterResume = false;
- }
- if( mPartialUpdateAvailable && mSwapBuffersWithDamage )
+#ifndef DALI_PROFILE_UBUNTU
+ if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
{
- mSwapBuffersWithDamage( mEglDisplay, eglSurface, &mDamagedRectArray[0], mDamagedRectArray.size()/4 );
+ DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" );
}
- else
+#endif //DALI_PROFILE_UBUNTU
+
+ // DALI_LOG_ERROR("EglImplementation::SwapBuffers()\n");
+ eglSwapBuffers( mEglDisplay, eglSurface );
+
+#ifndef DALI_PROFILE_UBUNTU
+ if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
{
- eglSwapBuffers( mEglDisplay, eglSurface );
+ 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;
+ }
-int EglImplementation::GetBufferAge( EGLSurface& eglSurface )
+ // 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;
+}
+
+void EglImplementation::SetDamageRegion( EGLSurface& eglSurface, std::vector< Rect< int > >& damagedRects )
{
- int bufferAge = 0;
- if ( eglSurface != EGL_NO_SURFACE && mIsKhrPartialUpdateSupported )
+ if( !mPartialUpdateRequired )
+ {
+ return;
+ }
+
+ if( eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
{
- if( !eglQuerySurface(mEglDisplay, eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge) )
+ EGLBoolean result = mEglSetDamageRegionKHR( mEglDisplay, eglSurface, reinterpret_cast< int* >( damagedRects.data() ), 1 );
+ if (result == EGL_FALSE)
{
- DALI_LOG_ERROR("EglImplementation::GetBufferAge() eglQuerySurface %s ", GetEglErrorString(eglGetError()) );
+ DALI_LOG_ERROR( "eglSetDamageRegionKHR(%d)\n", eglGetError() );
}
}
- return bufferAge;
}
-void EglImplementation::SetDamagedRect( std::vector<int> damagedRectArray, EGLSurface& eglSurface )
+void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects)
{
- mDamagedRectArray = damagedRectArray;
- if ( eglSurface != EGL_NO_SURFACE && mPartialUpdateAvailable && mEglSetDamageRegionKHR )
+ if (eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
{
- if( !mEglSetDamageRegionKHR( mEglDisplay, eglSurface, &damagedRectArray[0], damagedRectArray.size() / 4 ) )
+ if (!mPartialUpdateRequired )
{
- DALI_LOG_ERROR("EglImplementation::mEglSetDamageRegionKHR() error %s ", GetEglErrorString(eglGetError()) );
+ SwapBuffers(eglSurface);
+ return;
}
+
+#ifndef DALI_PROFILE_UBUNTU
+ if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
+ {
+ DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" );
+ }
+#endif //DALI_PROFILE_UBUNTU
+
+ 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());
+ }
+
+#ifndef DALI_PROFILE_UBUNTU
+ if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
+ {
+ DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
+ mSwapBufferCountAfterResume++;
+ }
+#endif //DALI_PROFILE_UBUNTU
}
}
// the surface is bound to the context, so set the context to null
MakeContextNull();
- // destroy the surface
- DestroySurface( eglSurface );
+ if( eglSurface )
+ {
+ // destroy the surface
+ DestroySurface( eglSurface );
+ }
// create the EGL surface
EGLSurface newEglSurface = CreateSurfaceWindow( window, mColorDepth );
void EglImplementation::SetFirstFrameAfterResume()
{
- mIsFirstFrameAfterResume = true;
+ mSwapBufferCountAfterResume = 0;
}
EGLDisplay EglImplementation::GetDisplay() const
}
}
+bool EglImplementation::IsPartialUpdateRequired() const
+{
+ return mPartialUpdateRequired;
+}
+
} // namespace Adaptor
} // namespace Internal