Merge "Modify native render surface for sync. with replace surface" into devel/master
[platform/core/uifw/dali-adaptor.git] / adaptors / common / gl / egl-implementation.cpp
1 /*
2  * Copyright (c) 2017 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 <gl/egl-implementation.h>
21
22 // EXTERNAL INCLUDES
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/common/dali-common.h>
25 #include <dali/public-api/common/dali-vector.h>
26
27 // INTERNAL INCLUDES
28 #include <gl/gl-implementation.h>
29 #include <gl/egl-debug.h>
30
31 namespace Dali
32 {
33
34 namespace Internal
35 {
36
37 namespace Adaptor
38 {
39
40 #define TEST_EGL_ERROR(lastCommand) \
41 { \
42   EGLint err = eglGetError(); \
43   if (err != EGL_SUCCESS) \
44   { \
45     DALI_LOG_ERROR("EGL error after %s\n", lastCommand); \
46     Egl::PrintError(err); \
47     DALI_ASSERT_ALWAYS(0 && "EGL error"); \
48   } \
49 }
50
51 EglImplementation::EglImplementation()
52   : mEglNativeDisplay(0),
53     mEglNativeWindow(0),
54     mCurrentEglNativePixmap(0),
55     mEglDisplay(0),
56     mEglConfig(0),
57     mEglContext(0),
58     mCurrentEglSurface(0),
59     mGlesInitialized(false),
60     mIsOwnSurface(true),
61     mContextCurrent(false),
62     mIsWindow(true),
63     mColorDepth(COLOR_DEPTH_24)
64 {
65 }
66
67 EglImplementation::~EglImplementation()
68 {
69   TerminateGles();
70 }
71
72 bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
73 {
74   if ( !mGlesInitialized )
75   {
76     mEglNativeDisplay = display;
77
78     //@todo see if we can just EGL_DEFAULT_DISPLAY instead
79     mEglDisplay = eglGetDisplay(mEglNativeDisplay);
80     EGLint error = eglGetError();
81
82     if( mEglDisplay == NULL && error != EGL_SUCCESS )
83     {
84       throw Dali::DaliException( "", "OpenGL ES is not supported");
85     }
86
87     EGLint majorVersion = 0;
88     EGLint minorVersion = 0;
89     if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
90     {
91       return false;
92     }
93     eglBindAPI(EGL_OPENGL_ES_API);
94
95     mContextAttribs.Clear();
96
97 #if DALI_GLES_VERSION >= 30
98
99     mContextAttribs.Reserve(5);
100     mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
101     mContextAttribs.PushBack( DALI_GLES_VERSION / 10 );
102     mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
103     mContextAttribs.PushBack( DALI_GLES_VERSION % 10 );
104
105 #else // DALI_GLES_VERSION >= 30
106
107     mContextAttribs.Reserve(3);
108     mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
109     mContextAttribs.PushBack( 2 );
110
111 #endif // DALI_GLES_VERSION >= 30
112
113     mContextAttribs.PushBack( EGL_NONE );
114
115     mGlesInitialized = true;
116     mIsOwnSurface = isOwnSurface;
117   }
118
119   return mGlesInitialized;
120 }
121
122 bool EglImplementation::CreateContext()
123 {
124   // make sure a context isn't created twice
125   DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
126
127   mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
128   TEST_EGL_ERROR("eglCreateContext render thread");
129
130   DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
131
132   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
133   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
134   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
135   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
136   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
137
138   return true;
139 }
140
141 void EglImplementation::DestroyContext()
142 {
143   DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
144
145   eglDestroyContext( mEglDisplay, mEglContext );
146   mEglContext = 0;
147 }
148
149 void EglImplementation::DestroySurface()
150 {
151   if(mIsOwnSurface && mCurrentEglSurface)
152   {
153     eglDestroySurface( mEglDisplay, mCurrentEglSurface );
154     mCurrentEglSurface = 0;
155   }
156 }
157
158 void EglImplementation::MakeContextCurrent()
159 {
160   mContextCurrent = true;
161
162   if(mIsOwnSurface)
163   {
164     eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
165   }
166
167   EGLint error = eglGetError();
168
169   if ( error != EGL_SUCCESS )
170   {
171     Egl::PrintError(error);
172
173     DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
174   }
175
176   // We want to display this information all the time, so use the LogMessage directly
177   Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
178       "            Vendor:        %s\n"
179       "            Version:       %s\n"
180       "            Client APIs:   %s\n"
181       "            Extensions:    %s\n",
182       eglQueryString(mEglDisplay, EGL_VENDOR),
183       eglQueryString(mEglDisplay, EGL_VERSION),
184       eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
185       eglQueryString(mEglDisplay, EGL_EXTENSIONS));
186 }
187
188 void EglImplementation::MakeCurrent( EGLNativePixmapType pixmap, EGLSurface eglSurface )
189 {
190   mCurrentEglNativePixmap = pixmap;
191   mCurrentEglSurface = eglSurface;
192
193   if(mIsOwnSurface)
194   {
195     eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
196   }
197
198   EGLint error = eglGetError();
199
200   if ( error != EGL_SUCCESS )
201   {
202     Egl::PrintError(error);
203
204     DALI_ASSERT_ALWAYS(false && "MakeCurrent failed!");
205   }
206 }
207
208 void EglImplementation::MakeContextNull()
209 {
210   mContextCurrent = false;
211   // clear the current context
212   eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
213 }
214
215 void EglImplementation::TerminateGles()
216 {
217   if ( mGlesInitialized )
218   {
219     // in latest Mali DDK (r2p3 ~ r3p0 in April, 2012),
220     // MakeContextNull should be called before eglDestroy surface
221     // to prevent crash in _mali_surface_destroy_callback
222     MakeContextNull();
223
224     if(mIsOwnSurface && mCurrentEglSurface)
225     {
226       eglDestroySurface(mEglDisplay, mCurrentEglSurface);
227     }
228     eglDestroyContext(mEglDisplay, mEglContext);
229
230     eglTerminate(mEglDisplay);
231
232     mEglDisplay = NULL;
233     mEglConfig  = NULL;
234     mEglContext = NULL;
235     mCurrentEglSurface = NULL;
236
237     mGlesInitialized = false;
238   }
239 }
240
241 bool EglImplementation::IsGlesInitialized() const
242 {
243   return mGlesInitialized;
244 }
245
246 void EglImplementation::SwapBuffers()
247 {
248   eglSwapBuffers( mEglDisplay, mCurrentEglSurface );
249 }
250
251 void EglImplementation::CopyBuffers()
252 {
253   eglCopyBuffers( mEglDisplay, mCurrentEglSurface, mCurrentEglNativePixmap );
254 }
255
256 void EglImplementation::WaitGL()
257 {
258   eglWaitGL();
259 }
260
261 void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
262 {
263   if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
264   {
265     return;
266   }
267
268   mIsWindow = isWindowType;
269
270   EGLint numConfigs;
271   Vector<EGLint> configAttribs;
272   configAttribs.Reserve(31);
273
274   if(isWindowType)
275   {
276     configAttribs.PushBack( EGL_SURFACE_TYPE );
277     configAttribs.PushBack( EGL_WINDOW_BIT );
278   }
279   else
280   {
281     configAttribs.PushBack( EGL_SURFACE_TYPE );
282     configAttribs.PushBack( EGL_PIXMAP_BIT );
283   }
284
285   configAttribs.PushBack( EGL_RENDERABLE_TYPE );
286
287 #if DALI_GLES_VERSION >= 30
288
289 #ifdef _ARCH_ARM_
290   configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
291 #else
292   // There is a bug in the desktop emulator
293   // Requesting for ES3 causes eglCreateContext even though it allows to ask
294   // for a configuration that supports GLES 3.0
295   configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
296 #endif // _ARCH_ARM_
297
298 #else // DALI_GLES_VERSION >= 30
299
300   Integration::Log::LogMessage( Integration::Log::DebugInfo, "Using OpenGL ES 2 \n" );
301   configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
302
303 #endif //DALI_GLES_VERSION >= 30
304
305 #if DALI_GLES_VERSION >= 30
306 // TODO: enable this flag when it becomes supported
307 //  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
308 //  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
309 #endif //DALI_GLES_VERSION >= 30
310
311   configAttribs.PushBack( EGL_RED_SIZE );
312   configAttribs.PushBack( 8 );
313   configAttribs.PushBack( EGL_GREEN_SIZE );
314   configAttribs.PushBack( 8 );
315   configAttribs.PushBack( EGL_BLUE_SIZE );
316   configAttribs.PushBack( 8 );
317
318   configAttribs.PushBack( EGL_ALPHA_SIZE );
319 #ifdef _ARCH_ARM_
320   configAttribs.PushBack( (depth == COLOR_DEPTH_32) ? 8 : 0 );
321 #else
322   // There is a bug in the desktop emulator
323   // setting EGL_ALPHA_SIZE to 8 results in eglChooseConfig failing
324   configAttribs.PushBack( 0 );
325 #endif // _ARCH_ARM_
326
327   configAttribs.PushBack( EGL_DEPTH_SIZE );
328   configAttribs.PushBack( 24 );
329   configAttribs.PushBack( EGL_STENCIL_SIZE );
330   configAttribs.PushBack( 8 );
331 #ifndef DALI_PROFILE_UBUNTU
332   configAttribs.PushBack( EGL_SAMPLES );
333   configAttribs.PushBack( 4 );
334   configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
335   configAttribs.PushBack( 1 );
336 #endif // DALI_PROFILE_UBUNTU
337   configAttribs.PushBack( EGL_NONE );
338
339   if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
340   {
341     EGLint error = eglGetError();
342     switch (error)
343     {
344       case EGL_BAD_DISPLAY:
345       {
346         DALI_LOG_ERROR("Display is not an EGL display connection\n");
347         break;
348       }
349       case EGL_BAD_ATTRIBUTE:
350       {
351         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");
352         break;
353       }
354       case EGL_NOT_INITIALIZED:
355       {
356         DALI_LOG_ERROR("Display has not been initialized\n");
357         break;
358       }
359       case EGL_BAD_PARAMETER:
360       {
361         DALI_LOG_ERROR("The parameter numConfig is NULL\n");
362         break;
363       }
364       default:
365       {
366         DALI_LOG_ERROR("Unknown error.\n");
367       }
368     }
369     DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
370   }
371
372   if ( numConfigs != 1 )
373   {
374     DALI_LOG_ERROR("No configurations found.\n");
375
376     TEST_EGL_ERROR("eglChooseConfig");
377   }
378 }
379
380 void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
381 {
382   DALI_ASSERT_ALWAYS( ( mCurrentEglSurface == 0 ) && "EGL surface already exists" );
383
384   mEglNativeWindow = window;
385   mColorDepth = depth;
386   mIsWindow = true;
387
388   // egl choose config
389   ChooseConfig(mIsWindow, mColorDepth);
390
391   mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
392   TEST_EGL_ERROR("eglCreateWindowSurface");
393
394   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
395 }
396
397 EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
398 {
399   mCurrentEglNativePixmap = pixmap;
400   mColorDepth = depth;
401   mIsWindow = false;
402
403   // egl choose config
404   ChooseConfig(mIsWindow, mColorDepth);
405
406   mCurrentEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL );
407   TEST_EGL_ERROR("eglCreatePixmapSurface");
408
409   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create pixmap surface failed" );
410
411   return mCurrentEglSurface;
412 }
413
414 bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window )
415 {
416   bool contextLost = false;
417
418   // display connection has not changed, then we can just create a new surface
419   //  the surface is bound to the context, so set the context to null
420   MakeContextNull();
421
422   // destroy the surface
423   DestroySurface();
424
425   // create the EGL surface
426   CreateSurfaceWindow( window, mColorDepth );
427
428   // set the context to be current with the new surface
429   MakeContextCurrent();
430
431   return contextLost;
432 }
433
434 bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface )
435 {
436   bool contextLost = false;
437
438   // display connection has not changed, then we can just create a new surface
439   // create the EGL surface
440   eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );
441
442   // set the eglSurface to be current
443   MakeCurrent( pixmap, eglSurface );
444
445   return contextLost;
446 }
447
448 EGLDisplay EglImplementation::GetDisplay() const
449 {
450   return mEglDisplay;
451 }
452
453 EGLDisplay EglImplementation::GetContext() const
454 {
455   return mEglContext;
456 }
457
458 } // namespace Adaptor
459
460 } // namespace Internal
461
462 } // namespace Dali