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