X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fgraphics%2Fgles%2Fegl-implementation.cpp;h=6e39644ee47cbf00a6ee714bfdd27cc530ea6a0c;hb=66ebc91833b3a2da6ca84c24c08f078de2d893be;hp=2d898f9a0d47d1ddba82807cae062203bf59e36a;hpb=a0e8db622c654ccb515b002128af5e8dc3a1e5a8;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/graphics/gles/egl-implementation.cpp b/dali/internal/graphics/gles/egl-implementation.cpp index 2d898f9..6e39644 100755 --- a/dali/internal/graphics/gles/egl-implementation.cpp +++ b/dali/internal/graphics/gles/egl-implementation.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -63,7 +63,8 @@ namespace Adaptor EglImplementation::EglImplementation( int multiSamplingLevel, Integration::DepthBufferAvailable depthBufferRequired, - Integration::StencilBufferAvailable stencilBufferRequired ) + Integration::StencilBufferAvailable stencilBufferRequired , + Integration::PartialUpdateAvailable partialUpdateRequired ) : mContextAttribs(), mEglNativeDisplay( 0 ), mEglNativeWindow( 0 ), @@ -81,9 +82,13 @@ EglImplementation::EglImplementation( int multiSamplingLevel, 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 ), + mFullSwapNextFrame( true ) { } @@ -98,12 +103,18 @@ bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwn { 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 == EGL_NO_DISPLAY ) + { + // If failed, try to get the default display connection + mEglDisplay = eglGetDisplay( EGL_DEFAULT_DISPLAY ); + } - if( mEglDisplay == NULL && error != EGL_SUCCESS ) + if( mEglDisplay == EGL_NO_DISPLAY ) { + // Still failed to get a display connection throw Dali::DaliException( "", "OpenGL ES is not supported"); } @@ -115,7 +126,6 @@ bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwn } eglBindAPI(EGL_OPENGL_ES_API); - mGlesInitialized = true; mIsOwnSurface = isOwnSurface; } @@ -138,12 +148,16 @@ bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwn } } + 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 ), @@ -168,6 +182,18 @@ bool EglImplementation::CreateContext() 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(eglGetProcAddress("eglSetDamageRegionKHR")); + if (!mEglSetDamageRegionKHR) + { + DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n"); + mPartialUpdateRequired = false; + } + mEglSwapBuffersWithDamageKHR = reinterpret_cast(eglGetProcAddress("eglSwapBuffersWithDamageKHR")); + if (!mEglSwapBuffersWithDamageKHR) + { + DALI_LOG_ERROR("Coudn't find eglSwapBuffersWithDamageKHR!\n"); + mPartialUpdateRequired = false; + } return true; } @@ -189,15 +215,28 @@ bool EglImplementation::CreateWindowContext( EGLContext& eglContext ) mEglWindowContexts.push_back( eglContext ); + mEglSetDamageRegionKHR = reinterpret_cast(eglGetProcAddress("eglSetDamageRegionKHR")); + if (!mEglSetDamageRegionKHR) + { + DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n"); + mPartialUpdateRequired = false; + } + mEglSwapBuffersWithDamageKHR = reinterpret_cast(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 ) @@ -319,7 +358,208 @@ void EglImplementation::SwapBuffers( EGLSurface& eglSurface ) } #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; +} + +void EglImplementation::SetFullSwapNextFrame() +{ + mFullSwapNextFrame = true; +} + +void mergeRects(Rect& mergingRect, const std::vector>& 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>>& damagedRectsList, const std::vector>& damagedRects) +{ + damagedRectsList.push_front(damagedRects); + if (damagedRectsList.size() > 4) // past triple buffers + current + { + damagedRectsList.pop_back(); + } +} + +void EglImplementation::SetDamage( EGLSurface& eglSurface, const std::vector>& damagedRects, Rect& 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 surfaceRect(0, 0, width, height); + + mSurfaceRect = surfaceRect; + + if (mFullSwapNextFrame) + { + insertRects(mBufferDamagedRects, std::vector>(1, surfaceRect)); + clippingRect = Rect(); + 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>(1, surfaceRect)); + clippingRect = Rect(); + 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>& 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(); + 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(&clippingRect), 1); + if (result == EGL_FALSE) + { + DALI_LOG_ERROR("eglSetDamageRegionKHR(%d)\n", eglGetError()); + } + } +} + +void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector>& damagedRects) +{ + if (eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context + { + if (!mPartialUpdateRequired || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > mSurfaceRect.Area() * 0.8) ) + { + SwapBuffers(eglSurface); + return; + } + +#ifndef DALI_PROFILE_UBUNTU + if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT ) + { + DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" ); + } +#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(mergedRects.data()), mergedRects.size()); + if (result == EGL_FALSE) + { + DALI_LOG_ERROR("eglSwapBuffersWithDamageKHR(%d)\n", eglGetError()); + } #ifndef DALI_PROFILE_UBUNTU if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT ) @@ -522,8 +762,11 @@ bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window, EGLSur // 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 );