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