[dali_1.9.19] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles / egl-implementation.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18
19 // CLASS HEADER
20 #include <dali/internal/graphics/gles/egl-implementation.h>
21
22 // EXTERNAL INCLUDES
23 #include <sstream>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/common/dali-vector.h>
26
27 // INTERNAL INCLUDES
28 #include <dali/public-api/dali-adaptor-common.h>
29 #include <dali/internal/graphics/gles/gl-implementation.h>
30 #include <dali/internal/graphics/gles/egl-debug.h>
31
32 // EGL constants use C style casts
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wold-style-cast"
35
36 namespace
37 {
38   const uint32_t THRESHOLD_SWAPBUFFER_COUNT = 5;
39   const uint32_t CHECK_EXTENSION_NUMBER = 2;
40   const std::string EGL_KHR_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context";
41   const std::string EGL_KHR_CREATE_CONTEXT = "EGL_KHR_create_context";
42 }
43
44 namespace Dali
45 {
46
47 namespace Internal
48 {
49
50 namespace Adaptor
51 {
52
53 #define TEST_EGL_ERROR(lastCommand) \
54 { \
55   EGLint err = eglGetError(); \
56   if (err != EGL_SUCCESS) \
57   { \
58     DALI_LOG_ERROR("EGL error after %s\n", lastCommand); \
59     Egl::PrintError(err); \
60     DALI_ASSERT_ALWAYS(0 && "EGL error"); \
61   } \
62 }
63
64 EglImplementation::EglImplementation( int multiSamplingLevel,
65                                       Integration::DepthBufferAvailable depthBufferRequired,
66                                       Integration::StencilBufferAvailable stencilBufferRequired ,
67                                       Integration::PartialUpdateAvailable partialUpdateRequired )
68 : mContextAttribs(),
69   mEglNativeDisplay( 0 ),
70   mEglNativeWindow( 0 ),
71   mCurrentEglNativePixmap( 0 ),
72   mEglDisplay( 0 ),
73   mEglConfig( 0 ),
74   mEglContext( 0 ),
75   mCurrentEglSurface( 0 ),
76   mCurrentEglContext( EGL_NO_CONTEXT ),
77   mMultiSamplingLevel( multiSamplingLevel ),
78   mGlesVersion( 30 ),
79   mColorDepth( COLOR_DEPTH_24 ),
80   mGlesInitialized( false ),
81   mIsOwnSurface( true ),
82   mIsWindow( true ),
83   mDepthBufferRequired( depthBufferRequired == Integration::DepthBufferAvailable::TRUE ),
84   mStencilBufferRequired( stencilBufferRequired == Integration::StencilBufferAvailable::TRUE ),
85   mPartialUpdateRequired( partialUpdateRequired == Integration::PartialUpdateAvailable::TRUE ),
86   mIsSurfacelessContextSupported( false ),
87   mIsKhrCreateContextSupported( false ),
88   mSwapBufferCountAfterResume( 0 ),
89   mEglSetDamageRegionKHR( 0 ),
90   mEglSwapBuffersWithDamageKHR( 0 ),
91   mBufferAge( 0 ),
92   mFullSwapNextFrame( true )
93 {
94 }
95
96 EglImplementation::~EglImplementation()
97 {
98   TerminateGles();
99 }
100
101 bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
102 {
103   if ( !mGlesInitialized )
104   {
105     mEglNativeDisplay = display;
106
107     // Try to get the display connection for the native display first
108     mEglDisplay = eglGetDisplay( mEglNativeDisplay );
109
110     if( mEglDisplay == EGL_NO_DISPLAY )
111     {
112       // If failed, try to get the default display connection
113       mEglDisplay = eglGetDisplay( EGL_DEFAULT_DISPLAY );
114     }
115
116     if( mEglDisplay == EGL_NO_DISPLAY )
117     {
118       // Still failed to get a display connection
119       throw Dali::DaliException( "", "OpenGL ES is not supported");
120     }
121
122     EGLint majorVersion = 0;
123     EGLint minorVersion = 0;
124     if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
125     {
126       return false;
127     }
128     eglBindAPI(EGL_OPENGL_ES_API);
129
130     mIsOwnSurface = isOwnSurface;
131   }
132
133   // Query EGL extensions to check whether surfaceless context is supported
134   const char* const extensionStr = eglQueryString( mEglDisplay, EGL_EXTENSIONS );
135   std::istringstream stream( extensionStr );
136   std::string currentExtension;
137   uint32_t extensionCheckCount = 0;
138   while( std::getline( stream, currentExtension, ' ' ) && extensionCheckCount < CHECK_EXTENSION_NUMBER )
139   {
140     if( currentExtension == EGL_KHR_SURFACELESS_CONTEXT )
141     {
142       mIsSurfacelessContextSupported = true;
143       extensionCheckCount++;
144     }
145     if( currentExtension == EGL_KHR_CREATE_CONTEXT )
146     {
147       mIsKhrCreateContextSupported = true;
148       extensionCheckCount++;
149     }
150   }
151
152   mGlesInitialized = true;
153
154   // We want to display this information all the time, so use the LogMessage directly
155   Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
156       "            Vendor:        %s\n"
157       "            Version:       %s\n"
158       "            Client APIs:   %s\n"
159       "            Extensions:    %s\n",
160       eglQueryString( mEglDisplay, EGL_VENDOR ),
161       eglQueryString( mEglDisplay, EGL_VERSION ),
162       eglQueryString( mEglDisplay, EGL_CLIENT_APIS ),
163       extensionStr);
164
165   return mGlesInitialized;
166 }
167
168 bool EglImplementation::CreateContext()
169 {
170   // make sure a context isn't created twice
171   DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
172
173   mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
174   TEST_EGL_ERROR("eglCreateContext render thread");
175
176   DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
177
178   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
179   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
180   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
181   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
182   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
183
184   mEglSetDamageRegionKHR = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
185   if (!mEglSetDamageRegionKHR)
186   {
187     DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n");
188     mPartialUpdateRequired = false;
189   }
190   mEglSwapBuffersWithDamageKHR = reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
191   if (!mEglSwapBuffersWithDamageKHR)
192   {
193     DALI_LOG_ERROR("Coudn't find eglSwapBuffersWithDamageKHR!\n");
194     mPartialUpdateRequired = false;
195   }
196   return true;
197 }
198
199 bool EglImplementation::CreateWindowContext( EGLContext& eglContext )
200 {
201   // make sure a context isn't created twice
202   DALI_ASSERT_ALWAYS( (eglContext == 0) && "EGL context recreated" );
203
204   eglContext = eglCreateContext(mEglDisplay, mEglConfig, mEglContext, &(mContextAttribs[0]));
205   TEST_EGL_ERROR("eglCreateContext render thread");
206
207   DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != eglContext && "EGL context not created" );
208
209   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
210   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
211   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
212   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
213   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
214
215   mEglWindowContexts.push_back( eglContext );
216
217   mEglSetDamageRegionKHR = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
218   if (!mEglSetDamageRegionKHR)
219   {
220     DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n");
221     mPartialUpdateRequired = false;
222   }
223   mEglSwapBuffersWithDamageKHR = reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
224   if (!mEglSwapBuffersWithDamageKHR)
225   {
226     DALI_LOG_ERROR("Coudn't find eglSwapBuffersWithDamageKHR!\n");
227     mPartialUpdateRequired = false;
228   }
229   return true;
230 }
231
232 void EglImplementation::DestroyContext( EGLContext& eglContext )
233 {
234   if( eglContext )
235   {
236     eglDestroyContext( mEglDisplay, eglContext );
237     eglContext = 0;
238   }
239 }
240
241 void EglImplementation::DestroySurface( EGLSurface& eglSurface )
242 {
243   if(mIsOwnSurface && eglSurface)
244   {
245     // Make context null to prevent crash in driver side
246     MakeContextNull();
247     eglDestroySurface( mEglDisplay, eglSurface );
248     eglSurface = 0;
249   }
250 }
251
252 void EglImplementation::MakeContextCurrent( EGLSurface eglSurface, EGLContext eglContext )
253 {
254   if (mCurrentEglContext == eglContext)
255   {
256     return;
257   }
258
259   mCurrentEglSurface = eglSurface;
260
261   if(mIsOwnSurface)
262   {
263     eglMakeCurrent( mEglDisplay, eglSurface, eglSurface, eglContext );
264
265     mCurrentEglContext = eglContext;
266   }
267
268   EGLint error = eglGetError();
269
270   if ( error != EGL_SUCCESS )
271   {
272     Egl::PrintError(error);
273
274     DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
275   }
276 }
277
278 void EglImplementation::MakeCurrent( EGLNativePixmapType pixmap, EGLSurface eglSurface )
279 {
280   if (mCurrentEglContext == mEglContext)
281   {
282     return;
283   }
284
285   mCurrentEglNativePixmap = pixmap;
286   mCurrentEglSurface = eglSurface;
287
288   if(mIsOwnSurface)
289   {
290     eglMakeCurrent( mEglDisplay, eglSurface, eglSurface, mEglContext );
291
292     mCurrentEglContext = mEglContext;
293   }
294
295   EGLint error = eglGetError();
296
297   if ( error != EGL_SUCCESS )
298   {
299     Egl::PrintError(error);
300
301     DALI_ASSERT_ALWAYS(false && "MakeCurrent failed!");
302   }
303 }
304
305 void EglImplementation::MakeContextNull()
306 {
307   // clear the current context
308   eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
309   mCurrentEglContext = EGL_NO_CONTEXT;
310 }
311
312 void EglImplementation::TerminateGles()
313 {
314   if ( mGlesInitialized )
315   {
316     // Make context null to prevent crash in driver side
317     MakeContextNull();
318
319     for ( auto eglSurface : mEglWindowSurfaces )
320     {
321       if(mIsOwnSurface && eglSurface)
322       {
323         eglDestroySurface(mEglDisplay, eglSurface);
324       }
325     }
326     eglDestroyContext(mEglDisplay, mEglContext);
327     for ( auto eglContext : mEglWindowContexts )
328     {
329       eglDestroyContext(mEglDisplay, eglContext);
330     }
331
332     eglTerminate(mEglDisplay);
333
334     mEglDisplay = NULL;
335     mEglConfig  = NULL;
336     mEglContext = NULL;
337     mCurrentEglSurface = NULL;
338     mCurrentEglContext = EGL_NO_CONTEXT;
339
340     mGlesInitialized = false;
341   }
342 }
343
344 bool EglImplementation::IsGlesInitialized() const
345 {
346   return mGlesInitialized;
347 }
348
349 void EglImplementation::SwapBuffers( EGLSurface& eglSurface )
350 {
351   if ( eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
352   {
353 #ifndef DALI_PROFILE_UBUNTU
354     if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
355     {
356       DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" );
357     }
358 #endif //DALI_PROFILE_UBUNTU
359
360     // DALI_LOG_ERROR("EglImplementation::SwapBuffers()\n");
361     eglSwapBuffers( mEglDisplay, eglSurface );
362     mFullSwapNextFrame = false;
363
364 #ifndef DALI_PROFILE_UBUNTU
365     if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
366     {
367       DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
368       mSwapBufferCountAfterResume++;
369     }
370 #endif //DALI_PROFILE_UBUNTU
371   }
372 }
373
374 EGLint EglImplementation::GetBufferAge(EGLSurface& eglSurface) const
375 {
376   EGLint age = 0;
377   eglQuerySurface(mEglDisplay, eglSurface, EGL_BUFFER_AGE_EXT, &age);
378   if (age < 0)
379   {
380     DALI_LOG_ERROR("eglQuerySurface(%d)\n", eglGetError());
381     age = 0;
382   }
383
384   // 0 - invalid buffer
385   // 1, 2, 3
386   if (age > 3)
387   {
388     DALI_LOG_ERROR("EglImplementation::GetBufferAge() buffer age %d > 3\n", age);
389     age = 0; // shoudn't be more than 3 back buffers, if there is just reset, I don't want to add extra history level
390   }
391
392   return age;
393 }
394
395 bool EglImplementation::DamageAreasSet() const
396 {
397   return (mDamagedAreas.size() ? true : false);
398 }
399
400 void EglImplementation::SetDamageAreas( std::vector<Dali::Rect<int>>& damagedAreas )
401 {
402   mFullSwapNextFrame = true;
403   mDamagedAreas = damagedAreas;
404 }
405
406 void EglImplementation::SetFullSwapNextFrame()
407 {
408   mFullSwapNextFrame = true;
409 }
410
411 void mergeRects(Rect<int>& mergingRect, const std::vector<Rect<int>>& rects)
412 {
413   uint32_t i = 0;
414   if (mergingRect.IsEmpty())
415   {
416     for (;i < rects.size(); i++)
417     {
418       if (!rects[i].IsEmpty())
419       {
420         mergingRect = rects[i];
421         break;
422       }
423     }
424   }
425
426   for (;i < rects.size(); i++)
427   {
428     mergingRect.Merge(rects[i]);
429   }
430 }
431
432 void insertRects(std::list<std::vector<Rect<int>>>& damagedRectsList, const std::vector<Rect<int>>& damagedRects)
433 {
434   damagedRectsList.push_front(damagedRects);
435   if (damagedRectsList.size() > 4) // past triple buffers + current
436   {
437     damagedRectsList.pop_back();
438   }
439 }
440
441 void EglImplementation::SetDamage( EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
442 {
443   if (!mPartialUpdateRequired)
444   {
445     return;
446   }
447
448   if (eglSurface != EGL_NO_SURFACE) // skip if using surfaceless context
449   {
450     EGLint width = 0;
451     EGLint height = 0;
452     eglQuerySurface(mEglDisplay, eglSurface, EGL_WIDTH, &width);
453     eglQuerySurface(mEglDisplay, eglSurface, EGL_HEIGHT, &height);
454     Rect<int> surfaceRect(0, 0, width, height);
455
456     mSurfaceRect = surfaceRect;
457
458     if (mFullSwapNextFrame)
459     {
460       mBufferAge = 0;
461       insertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
462       clippingRect = Rect<int>();
463       return;
464     }
465
466     EGLint bufferAge = GetBufferAge(eglSurface);
467     if (mDamagedAreas.size())
468     {
469       mBufferAge = bufferAge;
470       if (bufferAge == 0)
471       {
472         // Buffer age is reset
473         clippingRect = Rect<int>();
474         return;
475       }
476
477       mergeRects(clippingRect, mDamagedAreas);
478     }
479     else
480     {
481       // Buffer age 0 means the back buffer in invalid and requires full swap
482       if (!damagedRects.size() || bufferAge != mBufferAge || bufferAge == 0)
483       {
484         // No damage or buffer is out of order or buffer age is reset
485         mBufferAge = bufferAge;
486         insertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
487         clippingRect = Rect<int>();
488         return;
489       }
490
491       // We push current frame damaged rects here, zero index for current frame
492       mBufferAge = bufferAge;
493       insertRects(mBufferDamagedRects, damagedRects);
494
495       // Merge damaged rects into clipping rect
496       auto bufferDamagedRects = mBufferDamagedRects.begin();
497       while (bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
498       {
499         const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
500         mergeRects(clippingRect, rects);
501       }
502     }
503
504     if (!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * 0.8)
505     {
506       // clipping area too big or doesn't intersect surface rect
507       clippingRect = Rect<int>();
508       return;
509     }
510
511     // DALI_LOG_ERROR("eglSetDamageRegionKHR(%d, %d, %d, %d)\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height);
512     EGLBoolean result = mEglSetDamageRegionKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(&clippingRect), 1);
513     if (result == EGL_FALSE)
514     {
515       DALI_LOG_ERROR("eglSetDamageRegionKHR(%d)\n", eglGetError());
516     }
517   }
518 }
519
520 void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects)
521 {
522   if (eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
523   {
524     if (!mPartialUpdateRequired || mFullSwapNextFrame || mBufferAge == 0 || !damagedRects.size())
525     {
526       SwapBuffers(eglSurface);
527       return;
528     }
529
530 #ifndef DALI_PROFILE_UBUNTU
531     if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
532     {
533       DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" );
534     }
535 #endif //DALI_PROFILE_UBUNTU
536
537     if (mDamagedAreas.size())
538     {
539       // DALI_LOG_ERROR("EglImplementation::SwapBuffers(%d)\n", mDamagedAreas.size());
540       EGLBoolean result = mEglSwapBuffersWithDamageKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(mDamagedAreas.data()), mDamagedAreas.size());
541       if (result == EGL_FALSE)
542       {
543         DALI_LOG_ERROR("eglSwapBuffersWithDamageKHR(%d)\n", eglGetError());
544       }
545
546 #ifndef DALI_PROFILE_UBUNTU
547       if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
548       {
549         DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
550         mSwapBufferCountAfterResume++;
551       }
552 #endif //DALI_PROFILE_UBUNTU
553       return;
554     }
555
556     // current frame damaged rects were pushed by EglImplementation::SetDamage() to 0 index.
557     EGLint bufferAge = mBufferAge;
558     mCombinedDamagedRects.clear();
559
560     // Combine damaged rects from previous frames (beginning from bufferAge index) with the current frame (0 index)
561     auto bufferDamagedRects = mBufferDamagedRects.begin();
562     while (bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
563     {
564       const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
565       mCombinedDamagedRects.insert(mCombinedDamagedRects.end(), rects.begin(), rects.end());
566     }
567
568     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
569     // Could be optional and can be removed, needs to be checked with and without on platform
570     const int n = mCombinedDamagedRects.size();
571     for (int i = 0; i < n-1; i++)
572     {
573       if (mCombinedDamagedRects[i].IsEmpty())
574       {
575         continue;
576       }
577
578       for (int j = i+1; j < n; j++)
579       {
580         if (mCombinedDamagedRects[j].IsEmpty())
581         {
582           continue;
583         }
584
585         if (mCombinedDamagedRects[i].Intersects(mCombinedDamagedRects[j]))
586         {
587           mCombinedDamagedRects[i].Merge(mCombinedDamagedRects[j]);
588           mCombinedDamagedRects[j].width = 0;
589           mCombinedDamagedRects[j].height = 0;
590         }
591       }
592     }
593
594     int j = 0;
595     for (int i = 0; i < n; i++)
596     {
597       if (!mCombinedDamagedRects[i].IsEmpty())
598       {
599         mCombinedDamagedRects[j++] = mCombinedDamagedRects[i];
600       }
601     }
602
603     if (j != 0)
604     {
605       mCombinedDamagedRects.resize(j);
606     }
607
608     if (!mCombinedDamagedRects.size() || (mCombinedDamagedRects[0].Area() > mSurfaceRect.Area() * 0.8))
609     {
610       SwapBuffers(eglSurface);
611       return;
612     }
613
614     // DALI_LOG_ERROR("EglImplementation::SwapBuffers(%d)\n", mCombinedDamagedRects.size());
615     EGLBoolean result = mEglSwapBuffersWithDamageKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(mCombinedDamagedRects.data()), mCombinedDamagedRects.size());
616     if (result == EGL_FALSE)
617     {
618       DALI_LOG_ERROR("eglSwapBuffersWithDamageKHR(%d)\n", eglGetError());
619     }
620
621 #ifndef DALI_PROFILE_UBUNTU
622     if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
623     {
624       DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
625       mSwapBufferCountAfterResume++;
626     }
627 #endif //DALI_PROFILE_UBUNTU
628   }
629 }
630
631 void EglImplementation::CopyBuffers( EGLSurface& eglSurface )
632 {
633   eglCopyBuffers( mEglDisplay, eglSurface, mCurrentEglNativePixmap );
634 }
635
636 void EglImplementation::WaitGL()
637 {
638   eglWaitGL();
639 }
640
641 bool EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
642 {
643   if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
644   {
645     return true;
646   }
647
648   mColorDepth = depth;
649   mIsWindow = isWindowType;
650
651   EGLint numConfigs;
652   Vector<EGLint> configAttribs;
653   configAttribs.Reserve(31);
654
655   if(isWindowType)
656   {
657     configAttribs.PushBack( EGL_SURFACE_TYPE );
658     configAttribs.PushBack( EGL_WINDOW_BIT );
659   }
660   else
661   {
662     configAttribs.PushBack( EGL_SURFACE_TYPE );
663     configAttribs.PushBack( EGL_PIXMAP_BIT );
664   }
665
666   configAttribs.PushBack( EGL_RENDERABLE_TYPE );
667
668   if( mGlesVersion >= 30 )
669   {
670     configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
671   }
672   else
673   {
674     configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
675   }
676
677 // TODO: enable this flag when it becomes supported
678 //  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
679 //  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
680
681   configAttribs.PushBack( EGL_RED_SIZE );
682   configAttribs.PushBack( 8 );
683   configAttribs.PushBack( EGL_GREEN_SIZE );
684   configAttribs.PushBack( 8 );
685   configAttribs.PushBack( EGL_BLUE_SIZE );
686   configAttribs.PushBack( 8 );
687
688 //  For underlay video playback, we also need to set the alpha value of the 24/32bit window.
689   configAttribs.PushBack( EGL_ALPHA_SIZE );
690   configAttribs.PushBack( 8 );
691
692   configAttribs.PushBack( EGL_DEPTH_SIZE );
693   configAttribs.PushBack( mDepthBufferRequired ? 24 : 0 );
694   configAttribs.PushBack( EGL_STENCIL_SIZE );
695   configAttribs.PushBack( mStencilBufferRequired ? 8 : 0 );
696
697 #ifndef DALI_PROFILE_UBUNTU
698   if( mMultiSamplingLevel != EGL_DONT_CARE )
699   {
700     configAttribs.PushBack( EGL_SAMPLES );
701     configAttribs.PushBack( mMultiSamplingLevel );
702     configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
703     configAttribs.PushBack( 1 );
704   }
705 #endif // DALI_PROFILE_UBUNTU
706   configAttribs.PushBack( EGL_NONE );
707
708   // Ensure number of configs is set to 1 as on some drivers,
709   // eglChooseConfig succeeds but does not actually create a proper configuration.
710   if ( ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE ) ||
711        ( numConfigs != 1 ) )
712   {
713     if( mGlesVersion >= 30 )
714     {
715       mEglConfig = NULL;
716       DALI_LOG_ERROR("Fail to use OpenGL es 3.0. Retrying to use OpenGL es 2.0.");
717       return false;
718     }
719
720     if ( numConfigs != 1 )
721     {
722       DALI_LOG_ERROR("No configurations found.\n");
723
724       TEST_EGL_ERROR("eglChooseConfig");
725     }
726
727     EGLint error = eglGetError();
728     switch (error)
729     {
730       case EGL_BAD_DISPLAY:
731       {
732         DALI_LOG_ERROR("Display is not an EGL display connection\n");
733         break;
734       }
735       case EGL_BAD_ATTRIBUTE:
736       {
737         DALI_LOG_ERROR("The parameter configAttribs contains an invalid frame buffer configuration attribute or an attribute value that is unrecognized or out of range\n");
738         break;
739       }
740       case EGL_NOT_INITIALIZED:
741       {
742         DALI_LOG_ERROR("Display has not been initialized\n");
743         break;
744       }
745       case EGL_BAD_PARAMETER:
746       {
747         DALI_LOG_ERROR("The parameter numConfig is NULL\n");
748         break;
749       }
750       default:
751       {
752         DALI_LOG_ERROR("Unknown error.\n");
753       }
754     }
755     DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
756     return false;
757   }
758   Integration::Log::LogMessage(Integration::Log::DebugInfo, "Using OpenGL es %d.%d.\n", mGlesVersion / 10, mGlesVersion % 10 );
759
760   mContextAttribs.Clear();
761   if( mIsKhrCreateContextSupported )
762   {
763     mContextAttribs.Reserve(5);
764     mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
765     mContextAttribs.PushBack( mGlesVersion / 10 );
766     mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
767     mContextAttribs.PushBack( mGlesVersion % 10 );
768   }
769   else
770   {
771     mContextAttribs.Reserve(3);
772     mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
773     mContextAttribs.PushBack( mGlesVersion / 10 );
774   }
775   mContextAttribs.PushBack( EGL_NONE );
776
777   return true;
778 }
779
780 EGLSurface EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
781 {
782   mEglNativeWindow = window;
783   mColorDepth = depth;
784   mIsWindow = true;
785
786   // egl choose config
787   ChooseConfig(mIsWindow, mColorDepth);
788
789   mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
790   TEST_EGL_ERROR("eglCreateWindowSurface");
791
792   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
793
794   return mCurrentEglSurface;
795 }
796
797 EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
798 {
799   mCurrentEglNativePixmap = pixmap;
800   mColorDepth = depth;
801   mIsWindow = false;
802
803   // egl choose config
804   ChooseConfig(mIsWindow, mColorDepth);
805
806   mCurrentEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL );
807   TEST_EGL_ERROR("eglCreatePixmapSurface");
808
809   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create pixmap surface failed" );
810
811   return mCurrentEglSurface;
812 }
813
814 bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window, EGLSurface& eglSurface, EGLContext& eglContext )
815 {
816   bool contextLost = false;
817
818   // display connection has not changed, then we can just create a new surface
819   //  the surface is bound to the context, so set the context to null
820   MakeContextNull();
821
822   if( eglSurface )
823   {
824     // destroy the surface
825     DestroySurface( eglSurface );
826   }
827
828   // create the EGL surface
829   EGLSurface newEglSurface = CreateSurfaceWindow( window, mColorDepth );
830
831   // set the context to be current with the new surface
832   MakeContextCurrent( newEglSurface, eglContext );
833
834   return contextLost;
835 }
836
837 bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface )
838 {
839   bool contextLost = false;
840
841   // display connection has not changed, then we can just create a new surface
842   // create the EGL surface
843   eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );
844
845   // set the eglSurface to be current
846   MakeCurrent( pixmap, eglSurface );
847
848   return contextLost;
849 }
850
851 void EglImplementation::SetGlesVersion( const int32_t glesVersion )
852 {
853   mGlesVersion = glesVersion;
854 }
855
856 void EglImplementation::SetFirstFrameAfterResume()
857 {
858   mSwapBufferCountAfterResume = 0;
859 }
860
861 EGLDisplay EglImplementation::GetDisplay() const
862 {
863   return mEglDisplay;
864 }
865
866 EGLContext EglImplementation::GetContext() const
867 {
868   return mEglContext;
869 }
870
871 int32_t EglImplementation::GetGlesVersion() const
872 {
873   return mGlesVersion;
874 }
875
876 bool EglImplementation::IsSurfacelessContextSupported() const
877 {
878   return mIsSurfacelessContextSupported;
879 }
880
881 void EglImplementation::WaitClient()
882 {
883   // Wait for EGL to finish executing all rendering calls for the current context
884   if ( eglWaitClient() != EGL_TRUE )
885   {
886     TEST_EGL_ERROR("eglWaitClient");
887   }
888 }
889
890 } // namespace Adaptor
891
892 } // namespace Internal
893
894 } // namespace Dali
895
896 #pragma GCC diagnostic pop