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