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