2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <gl/egl-implementation.h>
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>
28 #include <ecore-x-render-surface.h>
29 #include <gl/gl-implementation.h>
40 #define TEST_EGL_ERROR(lastCommand) \
42 EGLint err = eglGetError(); \
43 if (err != EGL_SUCCESS) \
45 DALI_LOG_ERROR("EGL error after %s code=%d\n", lastCommand,err); \
46 DALI_ASSERT_ALWAYS(0 && "EGL error"); \
50 EglImplementation::EglImplementation()
51 : mEglNativeDisplay(0),
58 mGlesInitialized(false),
60 mContextCurrent(false),
62 mColorDepth(COLOR_DEPTH_24)
66 EglImplementation::~EglImplementation()
71 bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
73 if ( !mGlesInitialized )
75 mEglNativeDisplay = display;
77 //@todo see if we can just EGL_DEFAULT_DISPLAY instead
78 mEglDisplay = eglGetDisplay(mEglNativeDisplay);
80 EGLint majorVersion = 0;
81 EGLint minorVersion = 0;
82 if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
86 eglBindAPI(EGL_OPENGL_ES_API);
88 mContextAttribs.Clear();
90 #if DALI_GLES_VERSION >= 30
92 mContextAttribs.Reserve(5);
93 mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
94 mContextAttribs.PushBack( 3 );
95 mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
96 mContextAttribs.PushBack( 0 );
98 #else // DALI_GLES_VERSION >= 30
100 mContextAttribs.Reserve(3);
101 mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
102 mContextAttribs.PushBack( 2 );
104 #endif // DALI_GLES_VERSION >= 30
106 mContextAttribs.PushBack( EGL_NONE );
108 mGlesInitialized = true;
109 mIsOwnSurface = isOwnSurface;
112 return mGlesInitialized;
115 bool EglImplementation::CreateContext()
117 // make sure a context isn't created twice
118 DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
120 mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
121 TEST_EGL_ERROR("eglCreateContext render thread");
123 DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
125 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
126 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
127 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
128 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
129 DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
134 void EglImplementation::DestroyContext()
136 DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
138 eglDestroyContext( mEglDisplay, mEglContext );
142 void EglImplementation::DestroySurface()
144 if(mIsOwnSurface && mEglSurface)
146 eglDestroySurface( mEglDisplay, mEglSurface );
151 void EglImplementation::MakeContextCurrent()
153 mContextCurrent = true;
157 eglMakeCurrent( mEglDisplay, mEglSurface, mEglSurface, mEglContext );
160 EGLint error = eglGetError();
162 if ( error != EGL_SUCCESS )
166 case EGL_BAD_DISPLAY:
168 DALI_LOG_ERROR("EGL_BAD_DISPLAY : Display is not an EGL display connection");
171 case EGL_NOT_INITIALIZED:
173 DALI_LOG_ERROR("EGL_NOT_INITIALIZED : Display has not been initialized");
176 case EGL_BAD_SURFACE:
178 DALI_LOG_ERROR("EGL_BAD_SURFACE : Draw or read is not an EGL surface");
181 case EGL_BAD_CONTEXT:
183 DALI_LOG_ERROR("EGL_BAD_CONTEXT : Context is not an EGL rendering context");
188 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");
193 DALI_LOG_ERROR("EGL_BAD_ACCESS : Context is current to some other thread");
196 case EGL_BAD_NATIVE_PIXMAP:
198 DALI_LOG_ERROR("EGL_BAD_NATIVE_PIXMAP : A native pixmap underlying either draw or read is no longer valid.");
201 case EGL_BAD_NATIVE_WINDOW:
203 DALI_LOG_ERROR("EGL_BAD_NATIVE_WINDOW : A native window underlying either draw or read is no longer valid.");
206 case EGL_BAD_CURRENT_SURFACE:
208 DALI_LOG_ERROR("EGL_BAD_CURRENT_SURFACE : The previous context has unflushed commands and the previous surface is no longer valid.");
213 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");
216 case EGL_CONTEXT_LOST:
218 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");
223 DALI_LOG_ERROR("Unknown error");
227 DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
230 // We want to display this information all the time, so use the LogMessage directly
231 Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
236 eglQueryString(mEglDisplay, EGL_VENDOR),
237 eglQueryString(mEglDisplay, EGL_VERSION),
238 eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
239 eglQueryString(mEglDisplay, EGL_EXTENSIONS));
242 void EglImplementation::MakeContextNull()
244 mContextCurrent = false;
245 // clear the current context
246 eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
249 void EglImplementation::TerminateGles()
251 if ( mGlesInitialized )
253 // in latest Mali DDK (r2p3 ~ r3p0 in April, 2012),
254 // MakeContextNull should be called before eglDestroy surface
255 // to prevent crash in _mali_surface_destroy_callback
258 if(mIsOwnSurface && mEglSurface)
260 eglDestroySurface(mEglDisplay, mEglSurface);
262 eglDestroyContext(mEglDisplay, mEglContext);
264 eglTerminate(mEglDisplay);
271 mGlesInitialized = false;
275 bool EglImplementation::IsGlesInitialized() const
277 return mGlesInitialized;
280 void EglImplementation::SwapBuffers()
282 eglSwapBuffers( mEglDisplay, mEglSurface );
285 void EglImplementation::CopyBuffers()
287 eglCopyBuffers( mEglDisplay, mEglSurface, mEglNativePixmap );
290 void EglImplementation::WaitGL()
295 void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
297 if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
302 mIsWindow = isWindowType;
305 Vector<EGLint> configAttribs;
306 configAttribs.Reserve(31);
310 configAttribs.PushBack( EGL_SURFACE_TYPE );
311 configAttribs.PushBack( EGL_WINDOW_BIT );
315 configAttribs.PushBack( EGL_SURFACE_TYPE );
316 configAttribs.PushBack( EGL_PIXMAP_BIT );
319 configAttribs.PushBack( EGL_RENDERABLE_TYPE );
321 #if DALI_GLES_VERSION >= 30
324 configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
326 // There is a bug in the desktop emulator
327 // Requesting for ES3 causes eglCreateContext even though it allows to ask
328 // for a configuration that supports GLES 3.0
329 configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
332 #else // DALI_GLES_VERSION >= 30
334 DALI_LOG_WARNING( "Using OpenGL ES 2 \n" );
335 configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
337 #endif //DALI_GLES_VERSION >= 30
339 #if DALI_GLES_VERSION >= 30
340 // TODO: enable this flag when it becomes supported
341 // configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
342 // configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
343 #endif //DALI_GLES_VERSION >= 30
345 configAttribs.PushBack( EGL_RED_SIZE );
346 configAttribs.PushBack( 8 );
347 configAttribs.PushBack( EGL_GREEN_SIZE );
348 configAttribs.PushBack( 8 );
349 configAttribs.PushBack( EGL_BLUE_SIZE );
350 configAttribs.PushBack( 8 );
352 configAttribs.PushBack( EGL_ALPHA_SIZE );
354 configAttribs.PushBack( (depth == COLOR_DEPTH_32) ? 8 : 0 );
356 // There is a bug in the desktop emulator
357 // setting EGL_ALPHA_SIZE to 8 results in eglChooseConfig failing
358 configAttribs.PushBack( 0 );
361 configAttribs.PushBack( EGL_DEPTH_SIZE );
362 configAttribs.PushBack( 24 );
363 configAttribs.PushBack( EGL_STENCIL_SIZE );
364 configAttribs.PushBack( 8 );
365 #ifndef DALI_PROFILE_UBUNTU
366 configAttribs.PushBack( EGL_SAMPLES );
367 configAttribs.PushBack( 4 );
368 configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
369 configAttribs.PushBack( 1 );
370 #endif // DALI_PROFILE_UBUNTU
371 configAttribs.PushBack( EGL_NONE );
373 if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
375 EGLint error = eglGetError();
378 case EGL_BAD_DISPLAY:
380 DALI_LOG_ERROR("Display is not an EGL display connection\n");
383 case EGL_BAD_ATTRIBUTE:
385 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");
388 case EGL_NOT_INITIALIZED:
390 DALI_LOG_ERROR("Display has not been initialized\n");
393 case EGL_BAD_PARAMETER:
395 DALI_LOG_ERROR("The parameter numConfig is NULL\n");
400 DALI_LOG_ERROR("Unknown error.\n");
403 DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
406 if ( numConfigs != 1 )
408 DALI_LOG_ERROR("No configurations found.\n");
410 TEST_EGL_ERROR("eglChooseConfig");
415 void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
417 DALI_ASSERT_ALWAYS( ( mEglSurface == 0 ) && "EGL surface already exists" );
419 mEglNativeWindow = window;
424 ChooseConfig(mIsWindow, mColorDepth);
426 mEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
427 TEST_EGL_ERROR("eglCreateWindowSurface");
429 DALI_ASSERT_ALWAYS( mEglSurface && "Create window surface failed" );
432 void EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
434 DALI_ASSERT_ALWAYS( mEglSurface == 0 && "Cannot create more than one instance of surface pixmap" );
436 mEglNativePixmap = pixmap;
441 ChooseConfig(mIsWindow, mColorDepth);
443 mEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mEglNativePixmap, NULL );
444 TEST_EGL_ERROR("eglCreatePixmapSurface");
446 DALI_ASSERT_ALWAYS( mEglSurface && "Create pixmap surface failed" );
449 bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window, EGLNativeDisplayType display )
451 bool contextLost = false;
453 // the surface is bound to the context, so set the context to null
456 // destroy the surface
459 // If the display has not changed, then we can just create a new surface
460 if ( display == mEglNativeDisplay )
462 // create the EGL surface
463 CreateSurfaceWindow( window, mColorDepth );
465 // set the context to be current with the new surface
466 MakeContextCurrent();
468 else // the display has changed, we need to start egl with a new x-connection
470 // Note! this code path is untested
472 // this will release all EGL specific resources
473 eglTerminate( mEglDisplay );
475 mGlesInitialized = false;
477 // let the adaptor know that all resources have been lost
480 // re-initialise GLES with the new connection
481 InitializeGles( display );
483 // create the EGL surface
484 CreateSurfaceWindow( window, mColorDepth );
486 // create the OpenGL context
490 MakeContextCurrent();
496 bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLNativeDisplayType display )
498 bool contextLost = false;
500 // the surface is bound to the context, so set the context to null
503 // destroy the surface
506 // If the display has not changed, then we can just create a new surface
507 if ( display == mEglNativeDisplay )
509 // create the EGL surface
510 CreateSurfacePixmap( pixmap, mColorDepth );
512 // set the context to be current with the new surface
513 MakeContextCurrent();
515 else // the display has changed, we need to start egl with a new x-connection
517 // Note! this code path is untested
519 // this will release all EGL specific resources
520 eglTerminate( mEglDisplay );
522 mGlesInitialized = false;
524 // let the adaptor know that all resources have been lost
527 // re-initialise GLES with the new connection
528 InitializeGles( display );
530 // create the EGL surface
531 CreateSurfacePixmap( pixmap, mColorDepth );
533 // create the OpenGL context
537 MakeContextCurrent();
542 EGLDisplay EglImplementation::GetDisplay() const
547 EGLDisplay EglImplementation::GetContext() const
552 } // namespace Adaptor
554 } // namespace Internal