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