[dali_2.3.24] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles / egl-implementation.cpp
1 /*
2  * Copyright (c) 2024 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 // CLASS HEADER
19 #include <dali/internal/graphics/gles/egl-implementation.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/trace.h>
24 #include <dali/public-api/common/dali-vector.h>
25 #include <limits>
26 #include <sstream>
27
28 // INTERNAL INCLUDES
29 #include <dali/devel-api/adaptor-framework/environment-variable.h>
30 #include <dali/internal/graphics/gles/egl-debug.h>
31 #include <dali/internal/graphics/gles/gl-implementation.h>
32 #include <dali/internal/system/common/environment-variables.h>
33 #include <dali/internal/system/common/time-service.h>
34 #include <dali/public-api/dali-adaptor-common.h>
35
36 // EGL constants use C style casts
37 #pragma GCC diagnostic push
38 #pragma GCC diagnostic ignored "-Wold-style-cast"
39
40 namespace
41 {
42 #ifndef DALI_PROFILE_UBUNTU
43 const uint32_t THRESHOLD_SWAPBUFFER_COUNT = 20;
44 #else
45 const uint32_t THRESHOLD_SWAPBUFFER_COUNT = 5;
46 #endif
47 const uint32_t CHECK_EXTENSION_NUMBER                  = 4;
48 const uint32_t EGL_VERSION_SUPPORT_SURFACELESS_CONTEXT = 15;
49 const char*    EGL_KHR_SURFACELESS_CONTEXT             = "EGL_KHR_surfaceless_context";
50 const char*    EGL_KHR_CREATE_CONTEXT                  = "EGL_KHR_create_context";
51 const char*    EGL_KHR_PARTIAL_UPDATE                  = "EGL_KHR_partial_update";
52 const char*    EGL_KHR_SWAP_BUFFERS_WITH_DAMAGE        = "EGL_KHR_swap_buffers_with_damage";
53
54 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_EGL, true);
55
56 static uint32_t GetPerformanceLogThresholdTime()
57 {
58   auto     timeString = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_EGL_PERFORMANCE_LOG_THRESHOLD_TIME);
59   uint32_t time       = timeString ? static_cast<uint32_t>(std::atoi(timeString)) : std::numeric_limits<uint32_t>::max();
60   return time;
61 }
62
63 #define START_DURATION_CHECK()                         \
64   uint64_t startTimeNanoSeconds = 0ull;                \
65   uint64_t endTimeNanoSeconds   = 0ull;                \
66   if(mLogEnabled)                                      \
67   {                                                    \
68     TimeService::GetNanoseconds(startTimeNanoSeconds); \
69   }
70
71 #define FINISH_DURATION_CHECK(functionName)                                                                                                                \
72   if(mLogEnabled)                                                                                                                                          \
73   {                                                                                                                                                        \
74     TimeService::GetNanoseconds(endTimeNanoSeconds);                                                                                                       \
75     if(static_cast<uint32_t>((endTimeNanoSeconds - startTimeNanoSeconds) / 1000000ull) >= mLogThreshold)                                                   \
76     {                                                                                                                                                      \
77       DALI_LOG_RELEASE_INFO("%s takes long time! [%.6lf ms]\n", functionName, static_cast<double>(endTimeNanoSeconds - startTimeNanoSeconds) / 1000000.0); \
78     }                                                                                                                                                      \
79   }
80
81 } // namespace
82
83 namespace Dali
84 {
85 namespace Internal
86 {
87 namespace Adaptor
88 {
89 #define TEST_EGL_ERROR(lastCommand)                        \
90   {                                                        \
91     EGLint err = eglGetError();                            \
92     if(err != EGL_SUCCESS)                                 \
93     {                                                      \
94       DALI_LOG_ERROR("EGL error after %s\n", lastCommand); \
95       Egl::PrintError(err);                                \
96       DALI_ASSERT_ALWAYS(0 && "EGL error");                \
97     }                                                      \
98   }
99
100 EglImplementation::EglImplementation(int                                 multiSamplingLevel,
101                                      Integration::DepthBufferAvailable   depthBufferRequired,
102                                      Integration::StencilBufferAvailable stencilBufferRequired,
103                                      Integration::PartialUpdateAvailable partialUpdateRequired)
104 : mContextAttribs(),
105   mEglNativeDisplay(0),
106   mEglNativeWindow(0),
107   mCurrentEglNativePixmap(0),
108   mEglDisplay(0),
109   mEglConfig(0),
110   mEglContext(0),
111   mCurrentEglSurface(0),
112   mCurrentEglContext(EGL_NO_CONTEXT),
113   mMultiSamplingLevel(multiSamplingLevel),
114   mGlesVersion(30),
115   mColorDepth(COLOR_DEPTH_24),
116   mGlesInitialized(false),
117   mIsOwnSurface(true),
118   mIsWindow(true),
119   mDepthBufferRequired(depthBufferRequired == Integration::DepthBufferAvailable::TRUE),
120   mStencilBufferRequired(stencilBufferRequired == Integration::StencilBufferAvailable::TRUE),
121   mPartialUpdateRequired(partialUpdateRequired == Integration::PartialUpdateAvailable::TRUE),
122   mIsSurfacelessContextSupported(false),
123   mIsKhrCreateContextSupported(false),
124   mSwapBufferCountAfterResume(0),
125   mEglSetDamageRegionKHR(0),
126   mEglSwapBuffersWithDamageKHR(0)
127 {
128 }
129
130 EglImplementation::~EglImplementation()
131 {
132   TerminateGles();
133 }
134
135 bool EglImplementation::InitializeGles(EGLNativeDisplayType display, bool isOwnSurface)
136 {
137   if(!mGlesInitialized)
138   {
139     mEglNativeDisplay = display;
140
141     // Try to get the display connection for the native display first
142     mEglDisplay = eglGetDisplay(mEglNativeDisplay);
143
144     if(mEglDisplay == EGL_NO_DISPLAY)
145     {
146       // If failed, try to get the default display connection
147       mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
148     }
149
150     if(mEglDisplay == EGL_NO_DISPLAY)
151     {
152       // Still failed to get a display connection
153       throw Dali::DaliException("", "OpenGL ES is not supported");
154     }
155
156     EGLint majorVersion = 0;
157     EGLint minorVersion = 0;
158     if(!eglInitialize(mEglDisplay, &majorVersion, &minorVersion))
159     {
160       return false;
161     }
162     eglBindAPI(EGL_OPENGL_ES_API);
163
164     mIsOwnSurface = isOwnSurface;
165   }
166
167   const char* const versionStr   = eglQueryString(mEglDisplay, EGL_VERSION);
168   const char* const extensionStr = eglQueryString(mEglDisplay, EGL_EXTENSIONS);
169
170   // Query EGL extensions to check whether required extensions are supported
171   std::istringstream versionStream(versionStr);
172   std::string        majorVersion, minorVersion;
173   std::getline(versionStream, majorVersion, '.');
174   std::getline(versionStream, minorVersion);
175   uint32_t extensionCheckCount = 0;
176   if(stoul(majorVersion) * 10 + stoul(minorVersion) >= EGL_VERSION_SUPPORT_SURFACELESS_CONTEXT)
177   {
178     mIsSurfacelessContextSupported = true;
179     mIsKhrCreateContextSupported   = true;
180     extensionCheckCount += 2;
181   }
182
183   std::istringstream stream(extensionStr);
184   std::string        currentExtension;
185   bool               isKhrPartialUpdateSupported         = false;
186   bool               isKhrSwapBuffersWithDamageSupported = false;
187   while(std::getline(stream, currentExtension, ' ') && extensionCheckCount < CHECK_EXTENSION_NUMBER)
188   {
189     if(currentExtension == EGL_KHR_SURFACELESS_CONTEXT && !mIsSurfacelessContextSupported)
190     {
191       mIsSurfacelessContextSupported = true;
192       extensionCheckCount++;
193     }
194     if(currentExtension == EGL_KHR_CREATE_CONTEXT && !mIsKhrCreateContextSupported)
195     {
196       mIsKhrCreateContextSupported = true;
197       extensionCheckCount++;
198     }
199     if(currentExtension == EGL_KHR_PARTIAL_UPDATE)
200     {
201       isKhrPartialUpdateSupported = true;
202       extensionCheckCount++;
203     }
204     if(currentExtension == EGL_KHR_SWAP_BUFFERS_WITH_DAMAGE)
205     {
206       isKhrSwapBuffersWithDamageSupported = true;
207       extensionCheckCount++;
208     }
209   }
210
211   if(!isKhrPartialUpdateSupported || !isKhrSwapBuffersWithDamageSupported)
212   {
213     mPartialUpdateRequired = false;
214   }
215
216   mLogThreshold = GetPerformanceLogThresholdTime();
217   mLogEnabled   = mLogThreshold < std::numeric_limits<uint32_t>::max() ? true : false;
218
219   mGlesInitialized = true;
220
221   // We want to display this information all the time, so use the LogMessage directly
222   Integration::Log::LogMessage(Integration::Log::INFO,
223                                "EGL Information\n"
224                                "            PartialUpdate  %d\n"
225                                "            Vendor:        %s\n"
226                                "            Version:       %s\n"
227                                "            Client APIs:   %s\n"
228                                "            Extensions:    %s\n",
229                                mPartialUpdateRequired,
230                                eglQueryString(mEglDisplay, EGL_VENDOR),
231                                versionStr,
232                                eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
233                                extensionStr);
234
235   return mGlesInitialized;
236 }
237
238 bool EglImplementation::CreateContext()
239 {
240   // make sure a context isn't created twice
241   DALI_ASSERT_ALWAYS((mEglContext == 0) && "EGL context recreated");
242
243   mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
244   TEST_EGL_ERROR("eglCreateContext render thread");
245
246   DALI_ASSERT_ALWAYS(EGL_NO_CONTEXT != mEglContext && "EGL context not created");
247
248   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
249   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
250   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
251   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
252   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
253
254   mEglSetDamageRegionKHR = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
255   if(!mEglSetDamageRegionKHR)
256   {
257     DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n");
258     mPartialUpdateRequired = false;
259   }
260   mEglSwapBuffersWithDamageKHR = reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
261   if(!mEglSwapBuffersWithDamageKHR)
262   {
263     DALI_LOG_ERROR("Coudn't find eglSwapBuffersWithDamageKHR!\n");
264     mPartialUpdateRequired = false;
265   }
266   return true;
267 }
268
269 bool EglImplementation::CreateWindowContext(EGLContext& eglContext)
270 {
271   // make sure a context isn't created twice
272   DALI_ASSERT_ALWAYS((eglContext == 0) && "EGL context recreated");
273
274   eglContext = eglCreateContext(mEglDisplay, mEglConfig, mEglContext, &(mContextAttribs[0]));
275   TEST_EGL_ERROR("eglCreateContext render thread");
276
277   DALI_ASSERT_ALWAYS(EGL_NO_CONTEXT != eglContext && "EGL context not created");
278
279   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
280   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
281   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
282   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
283   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
284
285   mEglWindowContexts.push_back(eglContext);
286
287   mEglSetDamageRegionKHR = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
288   if(!mEglSetDamageRegionKHR)
289   {
290     DALI_LOG_ERROR("Coudn't find eglSetDamageRegionKHR!\n");
291     mPartialUpdateRequired = false;
292   }
293   mEglSwapBuffersWithDamageKHR = reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
294   if(!mEglSwapBuffersWithDamageKHR)
295   {
296     DALI_LOG_ERROR("Coudn't find eglSwapBuffersWithDamageKHR!\n");
297     mPartialUpdateRequired = false;
298   }
299   return true;
300 }
301
302 void EglImplementation::DestroyContext(EGLContext& eglContext)
303 {
304   if(eglContext)
305   {
306     eglDestroyContext(mEglDisplay, eglContext);
307     eglContext = 0;
308   }
309 }
310
311 void EglImplementation::DestroySurface(EGLSurface& eglSurface)
312 {
313   if(mIsOwnSurface && eglSurface)
314   {
315     // Make context null to prevent crash in driver side
316     MakeContextNull();
317     eglDestroySurface(mEglDisplay, eglSurface);
318     eglSurface = 0;
319   }
320 }
321
322 void EglImplementation::MakeContextCurrent(EGLSurface eglSurface, EGLContext eglContext)
323 {
324   if(mCurrentEglContext == eglContext)
325   {
326     return;
327   }
328
329   mCurrentEglSurface = eglSurface;
330
331   if(mIsOwnSurface)
332   {
333     eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, eglContext);
334
335     mCurrentEglContext = eglContext;
336   }
337
338   EGLint error = eglGetError();
339
340   if(error != EGL_SUCCESS)
341   {
342     Egl::PrintError(error);
343
344     DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
345   }
346 }
347
348 void EglImplementation::MakeCurrent(EGLNativePixmapType pixmap, EGLSurface eglSurface)
349 {
350   if(mCurrentEglContext == mEglContext)
351   {
352     return;
353   }
354
355   mCurrentEglNativePixmap = pixmap;
356   mCurrentEglSurface      = eglSurface;
357
358   if(mIsOwnSurface)
359   {
360     eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext);
361
362     mCurrentEglContext = mEglContext;
363   }
364
365   EGLint error = eglGetError();
366
367   if(error != EGL_SUCCESS)
368   {
369     Egl::PrintError(error);
370
371     DALI_ASSERT_ALWAYS(false && "MakeCurrent failed!");
372   }
373 }
374
375 void EglImplementation::MakeContextNull()
376 {
377   // clear the current context
378   eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
379   mCurrentEglContext = EGL_NO_CONTEXT;
380 }
381
382 void EglImplementation::TerminateGles()
383 {
384   if(mGlesInitialized)
385   {
386     // Make context null to prevent crash in driver side
387     MakeContextNull();
388
389     for(auto eglSurface : mEglWindowSurfaces)
390     {
391       if(mIsOwnSurface && eglSurface)
392       {
393         eglDestroySurface(mEglDisplay, eglSurface);
394       }
395     }
396     eglDestroyContext(mEglDisplay, mEglContext);
397     for(auto eglContext : mEglWindowContexts)
398     {
399       eglDestroyContext(mEglDisplay, eglContext);
400     }
401
402     eglTerminate(mEglDisplay);
403
404     mEglDisplay        = NULL;
405     mEglConfig         = NULL;
406     mEglContext        = NULL;
407     mCurrentEglSurface = NULL;
408     mCurrentEglContext = EGL_NO_CONTEXT;
409
410     mGlesInitialized = false;
411   }
412 }
413
414 bool EglImplementation::IsGlesInitialized() const
415 {
416   return mGlesInitialized;
417 }
418
419 void EglImplementation::SwapBuffers(EGLSurface& eglSurface)
420 {
421   if(eglSurface != EGL_NO_SURFACE) // skip if using surfaceless context
422   {
423     START_DURATION_CHECK();
424
425 #ifndef DALI_PROFILE_UBUNTU
426     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
427     {
428       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffers started. eglSurface(%p)\n", eglSurface);
429     }
430     DALI_TRACE_BEGIN(gTraceFilter, "DALI_EGL_SWAP_BUFFERS");
431 #endif //DALI_PROFILE_UBUNTU
432
433     // DALI_LOG_ERROR("EglImplementation::SwapBuffers()\n");
434     eglSwapBuffers(mEglDisplay, eglSurface);
435
436 #ifndef DALI_PROFILE_UBUNTU
437     DALI_TRACE_END(gTraceFilter, "DALI_EGL_SWAP_BUFFERS");
438     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
439     {
440       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffers finished.\n");
441       mSwapBufferCountAfterResume++;
442     }
443 #endif //DALI_PROFILE_UBUNTU
444
445     FINISH_DURATION_CHECK("eglSwapBuffers");
446   }
447 }
448
449 EGLint EglImplementation::GetBufferAge(EGLSurface& eglSurface) const
450 {
451   START_DURATION_CHECK();
452
453   EGLint age = 0;
454   eglQuerySurface(mEglDisplay, eglSurface, EGL_BUFFER_AGE_EXT, &age);
455   if(age < 0)
456   {
457     DALI_LOG_ERROR("eglQuerySurface(%d)\n", eglGetError());
458     age = 0;
459   }
460
461   FINISH_DURATION_CHECK("eglQuerySurface");
462
463   return age;
464 }
465
466 void EglImplementation::SetDamageRegion(EGLSurface& eglSurface, std::vector<Rect<int>>& damagedRects)
467 {
468   if(!mPartialUpdateRequired)
469   {
470     return;
471   }
472
473   if(eglSurface != EGL_NO_SURFACE) // skip if using surfaceless context
474   {
475     EGLBoolean result = mEglSetDamageRegionKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(damagedRects.data()), 1);
476     if(result == EGL_FALSE)
477     {
478       DALI_LOG_ERROR("eglSetDamageRegionKHR(0x%x)\n", eglGetError());
479     }
480   }
481 }
482
483 void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Rect<int>>& damagedRects)
484 {
485   if(eglSurface != EGL_NO_SURFACE) // skip if using surfaceless context
486   {
487     if(!mPartialUpdateRequired)
488     {
489       SwapBuffers(eglSurface);
490       return;
491     }
492
493     START_DURATION_CHECK();
494
495 #ifndef DALI_PROFILE_UBUNTU
496     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
497     {
498       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffersWithDamageKHR started. eglSurface(%p)\n", eglSurface);
499     }
500     DALI_TRACE_BEGIN(gTraceFilter, "DALI_EGL_SWAP_BUFFERS_KHR");
501 #endif //DALI_PROFILE_UBUNTU
502
503     EGLBoolean result = mEglSwapBuffersWithDamageKHR(mEglDisplay, eglSurface, reinterpret_cast<int*>(const_cast<std::vector<Rect<int>>&>(damagedRects).data()), damagedRects.size());
504     if(result == EGL_FALSE)
505     {
506       DALI_LOG_ERROR("eglSwapBuffersWithDamageKHR(%d)\n", eglGetError());
507     }
508
509 #ifndef DALI_PROFILE_UBUNTU
510     DALI_TRACE_END(gTraceFilter, "DALI_EGL_SWAP_BUFFERS_KHR");
511     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
512     {
513       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffersWithDamageKHR finished.\n");
514       mSwapBufferCountAfterResume++;
515     }
516 #endif //DALI_PROFILE_UBUNTU
517
518     FINISH_DURATION_CHECK("eglSwapBuffersWithDamageKHR");
519   }
520 }
521
522 void EglImplementation::CopyBuffers(EGLSurface& eglSurface)
523 {
524   eglCopyBuffers(mEglDisplay, eglSurface, mCurrentEglNativePixmap);
525 }
526
527 void EglImplementation::WaitGL()
528 {
529   eglWaitGL();
530 }
531
532 bool EglImplementation::ChooseConfig(bool isWindowType, ColorDepth depth)
533 {
534   if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
535   {
536     return true;
537   }
538
539   mColorDepth = depth;
540   mIsWindow   = isWindowType;
541
542   EGLint         numConfigs;
543   Vector<EGLint> configAttribs;
544   configAttribs.Reserve(31);
545
546   if(isWindowType)
547   {
548     configAttribs.PushBack(EGL_SURFACE_TYPE);
549     configAttribs.PushBack(EGL_WINDOW_BIT);
550   }
551   else
552   {
553     configAttribs.PushBack(EGL_SURFACE_TYPE);
554     configAttribs.PushBack(EGL_PIXMAP_BIT);
555   }
556
557   configAttribs.PushBack(EGL_RENDERABLE_TYPE);
558
559   if(mGlesVersion >= 30)
560   {
561     configAttribs.PushBack(EGL_OPENGL_ES3_BIT_KHR);
562   }
563   else
564   {
565     configAttribs.PushBack(EGL_OPENGL_ES2_BIT);
566   }
567
568   // TODO: enable this flag when it becomes supported
569   //  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
570   //  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
571
572   configAttribs.PushBack(EGL_RED_SIZE);
573   configAttribs.PushBack(8);
574   configAttribs.PushBack(EGL_GREEN_SIZE);
575   configAttribs.PushBack(8);
576   configAttribs.PushBack(EGL_BLUE_SIZE);
577   configAttribs.PushBack(8);
578
579   //  For underlay video playback, we also need to set the alpha value of the 24/32bit window.
580   // TODO: When the tbm queue of GlView is 24bit, do we have to set the alpha size??
581   configAttribs.PushBack(EGL_ALPHA_SIZE);
582   configAttribs.PushBack(8);
583
584   configAttribs.PushBack(EGL_DEPTH_SIZE);
585   configAttribs.PushBack(mDepthBufferRequired ? 24 : 0);
586   configAttribs.PushBack(EGL_STENCIL_SIZE);
587   configAttribs.PushBack(mStencilBufferRequired ? 8 : 0);
588
589   if(mMultiSamplingLevel != EGL_DONT_CARE)
590   {
591     configAttribs.PushBack(EGL_SAMPLES);
592     configAttribs.PushBack(mMultiSamplingLevel);
593     configAttribs.PushBack(EGL_SAMPLE_BUFFERS);
594     configAttribs.PushBack(1);
595   }
596
597   configAttribs.PushBack(EGL_NONE);
598
599   // Ensure number of configs is set to 1 as on some drivers,
600   // eglChooseConfig succeeds but does not actually create a proper configuration.
601   if((eglChooseConfig(mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs) != EGL_TRUE) ||
602      (numConfigs != 1))
603   {
604     if(mGlesVersion >= 30)
605     {
606       mEglConfig = NULL;
607       DALI_LOG_ERROR("Fail to use OpenGL es 3.0. Retrying to use OpenGL es 2.0.");
608       return false;
609     }
610
611     if(numConfigs != 1)
612     {
613       DALI_LOG_ERROR("No configurations found.\n");
614
615       TEST_EGL_ERROR("eglChooseConfig");
616     }
617
618     EGLint error = eglGetError();
619     switch(error)
620     {
621       case EGL_BAD_DISPLAY:
622       {
623         DALI_LOG_ERROR("Display is not an EGL display connection\n");
624         break;
625       }
626       case EGL_BAD_ATTRIBUTE:
627       {
628         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");
629         break;
630       }
631       case EGL_NOT_INITIALIZED:
632       {
633         DALI_LOG_ERROR("Display has not been initialized\n");
634         break;
635       }
636       case EGL_BAD_PARAMETER:
637       {
638         DALI_LOG_ERROR("The parameter numConfig is NULL\n");
639         break;
640       }
641       default:
642       {
643         DALI_LOG_ERROR("Unknown error.\n");
644       }
645     }
646     DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
647     return false;
648   }
649   Integration::Log::LogMessage(Integration::Log::INFO, "Using OpenGL es %d.%d.\n", mGlesVersion / 10, mGlesVersion % 10);
650
651   mContextAttribs.Clear();
652   if(mIsKhrCreateContextSupported)
653   {
654     mContextAttribs.Reserve(5);
655     mContextAttribs.PushBack(EGL_CONTEXT_MAJOR_VERSION_KHR);
656     mContextAttribs.PushBack(mGlesVersion / 10);
657     mContextAttribs.PushBack(EGL_CONTEXT_MINOR_VERSION_KHR);
658     mContextAttribs.PushBack(mGlesVersion % 10);
659   }
660   else
661   {
662     mContextAttribs.Reserve(3);
663     mContextAttribs.PushBack(EGL_CONTEXT_CLIENT_VERSION);
664     mContextAttribs.PushBack(mGlesVersion / 10);
665   }
666   mContextAttribs.PushBack(EGL_NONE);
667
668   return true;
669 }
670
671 EGLSurface EglImplementation::CreateSurfaceWindow(EGLNativeWindowType window, ColorDepth depth)
672 {
673   mEglNativeWindow = window;
674   mColorDepth      = depth;
675   mIsWindow        = true;
676
677   // egl choose config
678   ChooseConfig(mIsWindow, mColorDepth);
679
680   mCurrentEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mEglNativeWindow, NULL);
681   TEST_EGL_ERROR("eglCreateWindowSurface");
682
683   DALI_ASSERT_ALWAYS(mCurrentEglSurface && "Create window surface failed");
684
685   return mCurrentEglSurface;
686 }
687
688 EGLSurface EglImplementation::CreateSurfacePixmap(EGLNativePixmapType pixmap, ColorDepth depth)
689 {
690   mCurrentEglNativePixmap = pixmap;
691   mColorDepth             = depth;
692   mIsWindow               = false;
693
694   // egl choose config
695   ChooseConfig(mIsWindow, mColorDepth);
696
697   mCurrentEglSurface = eglCreatePixmapSurface(mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL);
698   TEST_EGL_ERROR("eglCreatePixmapSurface");
699
700   DALI_ASSERT_ALWAYS(mCurrentEglSurface && "Create pixmap surface failed");
701
702   return mCurrentEglSurface;
703 }
704
705 bool EglImplementation::ReplaceSurfaceWindow(EGLNativeWindowType window, EGLSurface& eglSurface, EGLContext& eglContext)
706 {
707   bool contextLost = false;
708
709   // display connection has not changed, then we can just create a new surface
710   //  the surface is bound to the context, so set the context to null
711   MakeContextNull();
712
713   if(eglSurface)
714   {
715     // destroy the surface
716     DestroySurface(eglSurface);
717   }
718
719   // create the EGL surface
720   EGLSurface newEglSurface = CreateSurfaceWindow(window, mColorDepth);
721
722   // set the context to be current with the new surface
723   MakeContextCurrent(newEglSurface, eglContext);
724
725   return contextLost;
726 }
727
728 bool EglImplementation::ReplaceSurfacePixmap(EGLNativePixmapType pixmap, EGLSurface& eglSurface)
729 {
730   bool contextLost = false;
731
732   // display connection has not changed, then we can just create a new surface
733   // create the EGL surface
734   eglSurface = CreateSurfacePixmap(pixmap, mColorDepth);
735
736   // set the eglSurface to be current
737   MakeCurrent(pixmap, eglSurface);
738
739   return contextLost;
740 }
741
742 void EglImplementation::SetGlesVersion(const int32_t glesVersion)
743 {
744   mGlesVersion = glesVersion;
745 }
746
747 void EglImplementation::SetFirstFrameAfterResume()
748 {
749   mSwapBufferCountAfterResume = 0;
750 }
751
752 EGLDisplay EglImplementation::GetDisplay() const
753 {
754   return mEglDisplay;
755 }
756
757 EGLContext EglImplementation::GetContext() const
758 {
759   return mEglContext;
760 }
761
762 int32_t EglImplementation::GetGlesVersion() const
763 {
764   return mGlesVersion;
765 }
766
767 bool EglImplementation::IsSurfacelessContextSupported() const
768 {
769   return mIsSurfacelessContextSupported;
770 }
771
772 void EglImplementation::WaitClient()
773 {
774   // Wait for EGL to finish executing all rendering calls for the current context
775   if(eglWaitClient() != EGL_TRUE)
776   {
777     TEST_EGL_ERROR("eglWaitClient");
778   }
779 }
780
781 bool EglImplementation::IsPartialUpdateRequired() const
782 {
783   return mPartialUpdateRequired;
784 }
785
786 } // namespace Adaptor
787
788 } // namespace Internal
789
790 } // namespace Dali
791
792 #pragma GCC diagnostic pop