Merge "Add environment variables for Pinch and Rotation gesture" into devel/master
[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 : mContextAttribs(),
68   mEglNativeDisplay( 0 ),
69   mEglNativeWindow( 0 ),
70   mCurrentEglNativePixmap( 0 ),
71   mEglDisplay( 0 ),
72   mEglConfig( 0 ),
73   mEglContext( 0 ),
74   mCurrentEglSurface( 0 ),
75   mCurrentEglContext( EGL_NO_CONTEXT ),
76   mMultiSamplingLevel( multiSamplingLevel ),
77   mGlesVersion( 30 ),
78   mColorDepth( COLOR_DEPTH_24 ),
79   mGlesInitialized( false ),
80   mIsOwnSurface( true ),
81   mIsWindow( true ),
82   mDepthBufferRequired( depthBufferRequired == Integration::DepthBufferAvailable::TRUE ),
83   mStencilBufferRequired( stencilBufferRequired == Integration::StencilBufferAvailable::TRUE ),
84   mIsSurfacelessContextSupported( false ),
85   mIsKhrCreateContextSupported( false ),
86   mSwapBufferCountAfterResume( 0 )
87 {
88 }
89
90 EglImplementation::~EglImplementation()
91 {
92   TerminateGles();
93 }
94
95 bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
96 {
97   if ( !mGlesInitialized )
98   {
99     mEglNativeDisplay = display;
100
101     //@todo see if we can just EGL_DEFAULT_DISPLAY instead
102     mEglDisplay = eglGetDisplay(mEglNativeDisplay);
103     EGLint error = eglGetError();
104
105     if( mEglDisplay == NULL && error != EGL_SUCCESS )
106     {
107       throw Dali::DaliException( "", "OpenGL ES is not supported");
108     }
109
110     EGLint majorVersion = 0;
111     EGLint minorVersion = 0;
112     if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
113     {
114       return false;
115     }
116     eglBindAPI(EGL_OPENGL_ES_API);
117
118     mIsOwnSurface = isOwnSurface;
119   }
120
121   // Query EGL extensions to check whether surfaceless context is supported
122   const char* const extensionStr = eglQueryString( mEglDisplay, EGL_EXTENSIONS );
123   std::istringstream stream( extensionStr );
124   std::string currentExtension;
125   uint32_t extensionCheckCount = 0;
126   while( std::getline( stream, currentExtension, ' ' ) && extensionCheckCount < CHECK_EXTENSION_NUMBER )
127   {
128     if( currentExtension == EGL_KHR_SURFACELESS_CONTEXT )
129     {
130       mIsSurfacelessContextSupported = true;
131       extensionCheckCount++;
132     }
133     if( currentExtension == EGL_KHR_CREATE_CONTEXT )
134     {
135       mIsKhrCreateContextSupported = true;
136       extensionCheckCount++;
137     }
138   }
139
140   mGlesInitialized = true;
141
142   // We want to display this information all the time, so use the LogMessage directly
143   Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
144       "            Vendor:        %s\n"
145       "            Version:       %s\n"
146       "            Client APIs:   %s\n"
147       "            Extensions:    %s\n",
148       eglQueryString( mEglDisplay, EGL_VENDOR ),
149       eglQueryString( mEglDisplay, EGL_VERSION ),
150       eglQueryString( mEglDisplay, EGL_CLIENT_APIS ),
151       extensionStr);
152
153   return mGlesInitialized;
154 }
155
156 bool EglImplementation::CreateContext()
157 {
158   // make sure a context isn't created twice
159   DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
160
161   mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
162   TEST_EGL_ERROR("eglCreateContext render thread");
163
164   DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
165
166   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
167   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
168   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
169   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
170   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
171
172   return true;
173 }
174
175 bool EglImplementation::CreateWindowContext( EGLContext& eglContext )
176 {
177   // make sure a context isn't created twice
178   DALI_ASSERT_ALWAYS( (eglContext == 0) && "EGL context recreated" );
179
180   eglContext = eglCreateContext(mEglDisplay, mEglConfig, mEglContext, &(mContextAttribs[0]));
181   TEST_EGL_ERROR("eglCreateContext render thread");
182
183   DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != eglContext && "EGL context not created" );
184
185   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
186   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
187   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
188   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
189   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
190
191   mEglWindowContexts.push_back( eglContext );
192
193   return true;
194 }
195
196 void EglImplementation::DestroyContext( EGLContext& eglContext )
197 {
198   DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
199
200   eglDestroyContext( mEglDisplay, eglContext );
201   eglContext = 0;
202 }
203
204 void EglImplementation::DestroySurface( EGLSurface& eglSurface )
205 {
206   if(mIsOwnSurface && eglSurface)
207   {
208     // Make context null to prevent crash in driver side
209     MakeContextNull();
210     eglDestroySurface( mEglDisplay, eglSurface );
211     eglSurface = 0;
212   }
213 }
214
215 void EglImplementation::MakeContextCurrent( EGLSurface eglSurface, EGLContext eglContext )
216 {
217   if (mCurrentEglContext == eglContext)
218   {
219     return;
220   }
221
222   mCurrentEglSurface = eglSurface;
223
224   if(mIsOwnSurface)
225   {
226     eglMakeCurrent( mEglDisplay, eglSurface, eglSurface, eglContext );
227
228     mCurrentEglContext = eglContext;
229   }
230
231   EGLint error = eglGetError();
232
233   if ( error != EGL_SUCCESS )
234   {
235     Egl::PrintError(error);
236
237     DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
238   }
239 }
240
241 void EglImplementation::MakeCurrent( EGLNativePixmapType pixmap, EGLSurface eglSurface )
242 {
243   if (mCurrentEglContext == mEglContext)
244   {
245     return;
246   }
247
248   mCurrentEglNativePixmap = pixmap;
249   mCurrentEglSurface = eglSurface;
250
251   if(mIsOwnSurface)
252   {
253     eglMakeCurrent( mEglDisplay, eglSurface, eglSurface, mEglContext );
254
255     mCurrentEglContext = mEglContext;
256   }
257
258   EGLint error = eglGetError();
259
260   if ( error != EGL_SUCCESS )
261   {
262     Egl::PrintError(error);
263
264     DALI_ASSERT_ALWAYS(false && "MakeCurrent failed!");
265   }
266 }
267
268 void EglImplementation::MakeContextNull()
269 {
270   // clear the current context
271   eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
272   mCurrentEglContext = EGL_NO_CONTEXT;
273 }
274
275 void EglImplementation::TerminateGles()
276 {
277   if ( mGlesInitialized )
278   {
279     // Make context null to prevent crash in driver side
280     MakeContextNull();
281
282     for ( auto eglSurface : mEglWindowSurfaces )
283     {
284       if(mIsOwnSurface && eglSurface)
285       {
286         eglDestroySurface(mEglDisplay, eglSurface);
287       }
288     }
289     eglDestroyContext(mEglDisplay, mEglContext);
290     for ( auto eglContext : mEglWindowContexts )
291     {
292       eglDestroyContext(mEglDisplay, eglContext);
293     }
294
295     eglTerminate(mEglDisplay);
296
297     mEglDisplay = NULL;
298     mEglConfig  = NULL;
299     mEglContext = NULL;
300     mCurrentEglSurface = NULL;
301     mCurrentEglContext = EGL_NO_CONTEXT;
302
303     mGlesInitialized = false;
304   }
305 }
306
307 bool EglImplementation::IsGlesInitialized() const
308 {
309   return mGlesInitialized;
310 }
311
312 void EglImplementation::SwapBuffers( EGLSurface& eglSurface )
313 {
314   if ( eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
315   {
316 #ifndef DALI_PROFILE_UBUNTU
317     if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
318     {
319       DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" );
320     }
321 #endif //DALI_PROFILE_UBUNTU
322
323     eglSwapBuffers( mEglDisplay, eglSurface );
324
325 #ifndef DALI_PROFILE_UBUNTU
326     if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
327     {
328       DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
329       mSwapBufferCountAfterResume++;
330     }
331 #endif //DALI_PROFILE_UBUNTU
332   }
333 }
334
335 void EglImplementation::CopyBuffers( EGLSurface& eglSurface )
336 {
337   eglCopyBuffers( mEglDisplay, eglSurface, mCurrentEglNativePixmap );
338 }
339
340 void EglImplementation::WaitGL()
341 {
342   eglWaitGL();
343 }
344
345 bool EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
346 {
347   if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
348   {
349     return true;
350   }
351
352   mColorDepth = depth;
353   mIsWindow = isWindowType;
354
355   EGLint numConfigs;
356   Vector<EGLint> configAttribs;
357   configAttribs.Reserve(31);
358
359   if(isWindowType)
360   {
361     configAttribs.PushBack( EGL_SURFACE_TYPE );
362     configAttribs.PushBack( EGL_WINDOW_BIT );
363   }
364   else
365   {
366     configAttribs.PushBack( EGL_SURFACE_TYPE );
367     configAttribs.PushBack( EGL_PIXMAP_BIT );
368   }
369
370   configAttribs.PushBack( EGL_RENDERABLE_TYPE );
371
372   if( mGlesVersion >= 30 )
373   {
374     configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
375   }
376   else
377   {
378     configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
379   }
380
381 // TODO: enable this flag when it becomes supported
382 //  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
383 //  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
384
385   configAttribs.PushBack( EGL_RED_SIZE );
386   configAttribs.PushBack( 8 );
387   configAttribs.PushBack( EGL_GREEN_SIZE );
388   configAttribs.PushBack( 8 );
389   configAttribs.PushBack( EGL_BLUE_SIZE );
390   configAttribs.PushBack( 8 );
391
392 //  For underlay video playback, we also need to set the alpha value of the 24/32bit window.
393   configAttribs.PushBack( EGL_ALPHA_SIZE );
394   configAttribs.PushBack( 8 );
395
396   configAttribs.PushBack( EGL_DEPTH_SIZE );
397   configAttribs.PushBack( mDepthBufferRequired ? 24 : 0 );
398   configAttribs.PushBack( EGL_STENCIL_SIZE );
399   configAttribs.PushBack( mStencilBufferRequired ? 8 : 0 );
400
401 #ifndef DALI_PROFILE_UBUNTU
402   if( mMultiSamplingLevel != EGL_DONT_CARE )
403   {
404     configAttribs.PushBack( EGL_SAMPLES );
405     configAttribs.PushBack( mMultiSamplingLevel );
406     configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
407     configAttribs.PushBack( 1 );
408   }
409 #endif // DALI_PROFILE_UBUNTU
410   configAttribs.PushBack( EGL_NONE );
411
412   // Ensure number of configs is set to 1 as on some drivers,
413   // eglChooseConfig succeeds but does not actually create a proper configuration.
414   if ( ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE ) ||
415        ( numConfigs != 1 ) )
416   {
417     if( mGlesVersion >= 30 )
418     {
419       mEglConfig = NULL;
420       DALI_LOG_ERROR("Fail to use OpenGL es 3.0. Retrying to use OpenGL es 2.0.");
421       return false;
422     }
423
424     if ( numConfigs != 1 )
425     {
426       DALI_LOG_ERROR("No configurations found.\n");
427
428       TEST_EGL_ERROR("eglChooseConfig");
429     }
430
431     EGLint error = eglGetError();
432     switch (error)
433     {
434       case EGL_BAD_DISPLAY:
435       {
436         DALI_LOG_ERROR("Display is not an EGL display connection\n");
437         break;
438       }
439       case EGL_BAD_ATTRIBUTE:
440       {
441         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");
442         break;
443       }
444       case EGL_NOT_INITIALIZED:
445       {
446         DALI_LOG_ERROR("Display has not been initialized\n");
447         break;
448       }
449       case EGL_BAD_PARAMETER:
450       {
451         DALI_LOG_ERROR("The parameter numConfig is NULL\n");
452         break;
453       }
454       default:
455       {
456         DALI_LOG_ERROR("Unknown error.\n");
457       }
458     }
459     DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
460     return false;
461   }
462   Integration::Log::LogMessage(Integration::Log::DebugInfo, "Using OpenGL es %d.%d.\n", mGlesVersion / 10, mGlesVersion % 10 );
463
464   mContextAttribs.Clear();
465   if( mIsKhrCreateContextSupported )
466   {
467     mContextAttribs.Reserve(5);
468     mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
469     mContextAttribs.PushBack( mGlesVersion / 10 );
470     mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
471     mContextAttribs.PushBack( mGlesVersion % 10 );
472   }
473   else
474   {
475     mContextAttribs.Reserve(3);
476     mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
477     mContextAttribs.PushBack( mGlesVersion / 10 );
478   }
479   mContextAttribs.PushBack( EGL_NONE );
480
481   return true;
482 }
483
484 EGLSurface EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
485 {
486   mEglNativeWindow = window;
487   mColorDepth = depth;
488   mIsWindow = true;
489
490   // egl choose config
491   ChooseConfig(mIsWindow, mColorDepth);
492
493   mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
494   TEST_EGL_ERROR("eglCreateWindowSurface");
495
496   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
497
498   return mCurrentEglSurface;
499 }
500
501 EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
502 {
503   mCurrentEglNativePixmap = pixmap;
504   mColorDepth = depth;
505   mIsWindow = false;
506
507   // egl choose config
508   ChooseConfig(mIsWindow, mColorDepth);
509
510   mCurrentEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL );
511   TEST_EGL_ERROR("eglCreatePixmapSurface");
512
513   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create pixmap surface failed" );
514
515   return mCurrentEglSurface;
516 }
517
518 bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window, EGLSurface& eglSurface, EGLContext& eglContext )
519 {
520   bool contextLost = false;
521
522   // display connection has not changed, then we can just create a new surface
523   //  the surface is bound to the context, so set the context to null
524   MakeContextNull();
525
526   if( eglSurface )
527   {
528     // destroy the surface
529     DestroySurface( eglSurface );
530   }
531
532   // create the EGL surface
533   EGLSurface newEglSurface = CreateSurfaceWindow( window, mColorDepth );
534
535   // set the context to be current with the new surface
536   MakeContextCurrent( newEglSurface, eglContext );
537
538   return contextLost;
539 }
540
541 bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface )
542 {
543   bool contextLost = false;
544
545   // display connection has not changed, then we can just create a new surface
546   // create the EGL surface
547   eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );
548
549   // set the eglSurface to be current
550   MakeCurrent( pixmap, eglSurface );
551
552   return contextLost;
553 }
554
555 void EglImplementation::SetGlesVersion( const int32_t glesVersion )
556 {
557   mGlesVersion = glesVersion;
558 }
559
560 void EglImplementation::SetFirstFrameAfterResume()
561 {
562   mSwapBufferCountAfterResume = 0;
563 }
564
565 EGLDisplay EglImplementation::GetDisplay() const
566 {
567   return mEglDisplay;
568 }
569
570 EGLContext EglImplementation::GetContext() const
571 {
572   return mEglContext;
573 }
574
575 int32_t EglImplementation::GetGlesVersion() const
576 {
577   return mGlesVersion;
578 }
579
580 bool EglImplementation::IsSurfacelessContextSupported() const
581 {
582   return mIsSurfacelessContextSupported;
583 }
584
585 void EglImplementation::WaitClient()
586 {
587   // Wait for EGL to finish executing all rendering calls for the current context
588   if ( eglWaitClient() != EGL_TRUE )
589   {
590     TEST_EGL_ERROR("eglWaitClient");
591   }
592 }
593
594 } // namespace Adaptor
595
596 } // namespace Internal
597
598 } // namespace Dali
599
600 #pragma GCC diagnostic pop