Merge "Emscripten minimal adaptor build" into devel/master
[platform/core/uifw/dali-adaptor.git] / adaptors / emscripten / egl-implementation-emscripten.cpp
1 /*
2 Copyright (c) 2000-2013 Samsung Electronics Co., Ltd All Rights Reserved
3
4 This file is part of Dali Adaptor
5
6 PROPRIETARY/CONFIDENTIAL
7
8 This software is the confidential and proprietary information of
9 SAMSUNG ELECTRONICS ("Confidential Information"). You shall not
10 disclose such Confidential Information and shall use it only in
11 accordance with the terms of the license agreement you entered
12 into with SAMSUNG ELECTRONICS.
13
14 SAMSUNG make no representations or warranties about the suitability
15 of the software, either express or implied, including but not limited
16 to the implied warranties of merchantability, fitness for a particular
17 purpose, or non-infringement. SAMSUNG shall not be liable for any
18 damages suffered by licensee as a result of using, modifying or
19 distributing this software or its derivatives.
20 */
21
22
23 // CLASS HEADER
24 #include <gl/egl-implementation.h>
25
26 // EXTERNAL INCLUDES
27 #include <iostream>
28 #include <dali/integration-api/debug.h>
29 #include <dali/public-api/common/dali-common.h>
30 #include <dali/public-api/common/dali-vector.h>
31
32 // INTERNAL INCLUDES
33 namespace
34 {
35
36 #if defined(DEBUG_ENABLED)
37
38 void PrintConfigs(EGLDisplay d)
39 {
40   EGLint numConfigs;
41
42   eglGetConfigs(d, NULL, 0, &numConfigs);
43   EGLConfig *configs = new EGLConfig[numConfigs];
44
45   eglGetConfigs(d, configs, numConfigs, &numConfigs);
46
47   printf("Configurations: N=%d\n", numConfigs);
48   printf(" - config id\n");
49   printf(" - buffer size\n");
50   printf(" - level\n");
51   printf(" - double buffer\n");
52   printf(" - stereo\n");
53   printf(" - r, g, b\n");
54   printf(" - depth\n");
55   printf(" - stencil\n");
56
57   printf("     bf lv d st colorbuffer dp st   supported \n");
58   printf("  id sz  l b ro  r  g  b  a th cl   surfaces  \n");
59   printf("----------------------------------------------\n");
60   for (EGLint i = 0; i < numConfigs; i++) {
61     EGLint id, size, level;
62     EGLint red, green, blue, alpha;
63     EGLint depth, stencil;
64     EGLint surfaces;
65     EGLint doubleBuf = 1, stereo = 0;
66     char surfString[100] = "";
67
68     eglGetConfigAttrib(d, configs[i], EGL_CONFIG_ID, &id);
69     eglGetConfigAttrib(d, configs[i], EGL_BUFFER_SIZE, &size);
70     eglGetConfigAttrib(d, configs[i], EGL_LEVEL, &level);
71
72     eglGetConfigAttrib(d, configs[i], EGL_RED_SIZE, &red);
73     eglGetConfigAttrib(d, configs[i], EGL_GREEN_SIZE, &green);
74     eglGetConfigAttrib(d, configs[i], EGL_BLUE_SIZE, &blue);
75     eglGetConfigAttrib(d, configs[i], EGL_ALPHA_SIZE, &alpha);
76     eglGetConfigAttrib(d, configs[i], EGL_DEPTH_SIZE, &depth);
77     eglGetConfigAttrib(d, configs[i], EGL_STENCIL_SIZE, &stencil);
78     eglGetConfigAttrib(d, configs[i], EGL_SURFACE_TYPE, &surfaces);
79
80     if (surfaces & EGL_WINDOW_BIT)
81       strcat(surfString, "win,");
82     if (surfaces & EGL_PBUFFER_BIT)
83       strcat(surfString, "pb,");
84     if (surfaces & EGL_PIXMAP_BIT)
85       strcat(surfString, "pix,");
86     if (strlen(surfString) > 0)
87       surfString[strlen(surfString) - 1] = 0;
88
89     printf("0x%02x %2d %2d %c  %c %2d %2d %2d %2d %2d %2d   %-12s\n",
90            id, size, level,
91            doubleBuf ? 'y' : '.',
92            stereo ? 'y' : '.',
93            red, green, blue, alpha,
94            depth, stencil, surfString);
95   }
96
97   delete [] configs;
98 }
99
100 #endif
101
102 } // namespace anon
103
104 namespace Dali
105 {
106 namespace Internal
107 {
108 namespace Adaptor
109 {
110
111 #define TEST_EGL_ERROR(lastCommand) \
112 { \
113   EGLint err = eglGetError(); \
114   if (err != EGL_SUCCESS) \
115   { \
116     printf("EGL error after %s code=%x\n", lastCommand, err); \
117     DALI_LOG_ERROR("EGL error after %s code=%x\n", lastCommand,err); \
118     DALI_ASSERT_ALWAYS(0 && "EGL error");                            \
119   } \
120 }
121
122 EglImplementation::EglImplementation()
123   : mEglNativeDisplay(0),
124     mCurrentEglNativePixmap(0),
125     mEglDisplay(0),
126     mEglConfig(0),
127     mEglContext(0),
128     mCurrentEglSurface(0),
129     mGlesInitialized(false),
130     mIsOwnSurface(true),
131     mContextCurrent(false),
132     mIsWindow(true),
133     mColorDepth(COLOR_DEPTH_24)
134 {
135 }
136
137 EglImplementation::~EglImplementation()
138 {
139   TerminateGles();
140 }
141
142 bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
143 {
144   if ( !mGlesInitialized )
145   {
146     mEglNativeDisplay = display;
147
148     //@todo see if we can just EGL_DEFAULT_DISPLAY instead
149     mEglDisplay = eglGetDisplay(mEglNativeDisplay);
150
151     EGLint majorVersion = 0;
152     EGLint minorVersion = 0;
153     if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
154     {
155       return false;
156     }
157     eglBindAPI(EGL_OPENGL_ES_API);
158
159 #if defined(DEBUG_ENABLED)
160     PrintConfigs(mEglDisplay);
161 #endif
162
163     mContextAttribs.Clear();
164
165 #if DALI_GLES_VERSION >= 30
166
167     mContextAttribs.Reserve(5);
168     mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
169     mContextAttribs.PushBack( 3 );
170     mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
171     mContextAttribs.PushBack( 0 );
172
173 #else // DALI_GLES_VERSION >= 30
174
175     mContextAttribs.Reserve(3);
176     mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
177     mContextAttribs.PushBack( 2 );
178
179 #endif // DALI_GLES_VERSION >= 30
180
181     mContextAttribs.PushBack( EGL_NONE );
182
183     mGlesInitialized = true;
184     mIsOwnSurface = isOwnSurface;
185   }
186
187   return mGlesInitialized;
188 }
189
190 bool EglImplementation::CreateContext()
191 {
192   // make sure a context isn't created twice
193   DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
194   DALI_ASSERT_ALWAYS( mGlesInitialized );
195
196   mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
197
198   // if emscripten ignore this (egl spec says non gles2 implementation must return EGL_BAD_MATCH if it doesnt support gles2)
199   // so just ignore error for now....
200   // TEST_EGL_ERROR("eglCreateContext render thread");
201   // DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
202
203   return true;
204 }
205
206 void EglImplementation::DestroyContext()
207 {
208   DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
209
210   eglDestroyContext( mEglDisplay, mEglContext );
211   mEglContext = 0;
212 }
213
214 void EglImplementation::DestroySurface()
215 {
216   if(mIsOwnSurface && mCurrentEglSurface)
217   {
218     eglDestroySurface( mEglDisplay, mCurrentEglSurface );
219     mCurrentEglSurface = 0;
220   }
221 }
222
223 void EglImplementation::MakeContextCurrent()
224 {
225   mContextCurrent = true;
226
227   if(mIsOwnSurface)
228   {
229     eglMakeCurrent( mEglDisplay, mCurrentEglSurface, mCurrentEglSurface, mEglContext );
230   }
231
232   EGLint error = eglGetError();
233
234   if ( error != EGL_SUCCESS )
235   {
236     switch (error)
237     {
238       case EGL_BAD_DISPLAY:
239       {
240         DALI_LOG_ERROR("EGL_BAD_DISPLAY : Display is not an EGL display connection");
241         break;
242       }
243       case EGL_NOT_INITIALIZED:
244       {
245         DALI_LOG_ERROR("EGL_NOT_INITIALIZED : Display has not been initialized");
246         break;
247       }
248       case EGL_BAD_SURFACE:
249       {
250         DALI_LOG_ERROR("EGL_BAD_SURFACE : Draw or read is not an EGL surface");
251         break;
252       }
253       case EGL_BAD_CONTEXT:
254       {
255         DALI_LOG_ERROR("EGL_BAD_CONTEXT : Context is not an EGL rendering context");
256         break;
257       }
258       case EGL_BAD_MATCH:
259       {
260         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");
261         break;
262       }
263       case EGL_BAD_ACCESS:
264       {
265         DALI_LOG_ERROR("EGL_BAD_ACCESS : Context is current to some other thread");
266         break;
267       }
268       case EGL_BAD_NATIVE_PIXMAP:
269       {
270         DALI_LOG_ERROR("EGL_BAD_NATIVE_PIXMAP : A native pixmap underlying either draw or read is no longer valid.");
271         break;
272       }
273       case EGL_BAD_NATIVE_WINDOW:
274       {
275         DALI_LOG_ERROR("EGL_BAD_NATIVE_WINDOW : A native window underlying either draw or read is no longer valid.");
276         break;
277       }
278       case EGL_BAD_CURRENT_SURFACE:
279       {
280         DALI_LOG_ERROR("EGL_BAD_CURRENT_SURFACE : The previous context has unflushed commands and the previous surface is no longer valid.");
281         break;
282       }
283       case EGL_BAD_ALLOC:
284       {
285         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");
286         break;
287       }
288       case EGL_CONTEXT_LOST:
289       {
290         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");
291         break;
292       }
293       default:
294       {
295         DALI_LOG_ERROR("Unknown error");
296         break;
297       }
298     }
299     DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
300   }
301
302   DALI_LOG_WARNING("- EGL Information\nVendor: %s\nVersion: %s\nClient APIs: %s\nExtensions: %s\n",
303                    eglQueryString(mEglDisplay, EGL_VENDOR),
304                    eglQueryString(mEglDisplay, EGL_VERSION),
305                    eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
306                    eglQueryString(mEglDisplay, EGL_EXTENSIONS));
307
308 }
309
310 void EglImplementation::MakeContextNull()
311 {
312   mContextCurrent = false;
313   // clear the current context
314   eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
315 }
316
317 void EglImplementation::TerminateGles()
318 {
319   if ( mGlesInitialized )
320   {
321     // in latest Mali DDK (r2p3 ~ r3p0 in April, 2012),
322     // MakeContextNull should be called before eglDestroy surface
323     // to prevent crash in _mali_surface_destroy_callback
324     MakeContextNull();
325
326     if(mIsOwnSurface && mCurrentEglSurface)
327     {
328       eglDestroySurface(mEglDisplay, mCurrentEglSurface);
329     }
330     eglDestroyContext(mEglDisplay, mEglContext);
331
332     eglTerminate(mEglDisplay);
333
334     mEglDisplay = NULL;
335     mEglConfig  = NULL;
336     mEglContext = NULL;
337     mCurrentEglSurface = NULL;
338
339     mGlesInitialized = false;
340   }
341 }
342
343 bool EglImplementation::IsGlesInitialized() const
344 {
345   return mGlesInitialized;
346 }
347
348 void EglImplementation::SwapBuffers()
349 {
350   eglSwapBuffers( mEglDisplay, mCurrentEglSurface );
351 }
352
353 void EglImplementation::CopyBuffers()
354 {
355   eglCopyBuffers( mEglDisplay, mCurrentEglSurface, mCurrentEglNativePixmap );
356 }
357
358 void EglImplementation::WaitGL()
359 {
360   eglWaitGL();
361 }
362
363 void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
364 {
365   if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
366   {
367     return;
368   }
369
370   mIsWindow = isWindowType;
371
372   EGLint numConfigs;
373   Vector<EGLint> configAttribs;
374   configAttribs.Reserve(31);
375
376   if(isWindowType)
377   {
378     configAttribs.PushBack( EGL_SURFACE_TYPE );
379     configAttribs.PushBack( EGL_WINDOW_BIT );
380   }
381   else
382   {
383     DALI_ASSERT_ALWAYS(!"uninplemented");
384     configAttribs.PushBack( EGL_SURFACE_TYPE );
385     configAttribs.PushBack( EGL_PIXMAP_BIT );
386   }
387
388   configAttribs.PushBack( EGL_RENDERABLE_TYPE );
389
390 #if DALI_GLES_VERSION >= 30
391   DALI_ASSERT_ALWAYS(!"uninplemented");
392
393 #ifdef _ARCH_ARM_
394   configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
395 #else
396   // There is a bug in the desktop emulator
397   // Requesting for ES3 causes eglCreateContext even though it allows to ask
398   // for a configuration that supports GLES 3.0
399   configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
400 #endif // _ARCH_ARM_
401
402 #else // DALI_GLES_VERSION >= 30
403
404   configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
405
406 #endif //DALI_GLES_VERSION >= 30
407
408   configAttribs.PushBack( EGL_RED_SIZE );
409   configAttribs.PushBack( 8 );
410   configAttribs.PushBack( EGL_GREEN_SIZE );
411   configAttribs.PushBack( 8 );
412   configAttribs.PushBack( EGL_BLUE_SIZE );
413   configAttribs.PushBack( 8 );
414
415   //
416   // Setting the alpha crashed .... need SDL_SetVideo(...) with alpha somehow??
417   //
418
419   configAttribs.PushBack( EGL_ALPHA_SIZE );
420   configAttribs.PushBack( 8 );
421   configAttribs.PushBack( EGL_DEPTH_SIZE );
422   configAttribs.PushBack( 24 );
423
424   configAttribs.PushBack( EGL_NONE );
425
426   if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
427   {
428     EGLint error = eglGetError();
429     switch (error)
430     {
431       case EGL_BAD_DISPLAY:
432       {
433         DALI_LOG_ERROR("Display is not an EGL display connection");
434         break;
435       }
436       case EGL_BAD_ATTRIBUTE:
437       {
438         DALI_LOG_ERROR("The parameter confirAttribs contains an invalid frame buffer configuration attribute or an attribute value that is unrecognized or out of range");
439         break;
440       }
441       case EGL_NOT_INITIALIZED:
442       {
443         DALI_LOG_ERROR("Display has not been initialized");
444         break;
445       }
446       case EGL_BAD_PARAMETER:
447       {
448         DALI_LOG_ERROR("The parameter numConfig is NULL");
449         break;
450       }
451       default:
452       {
453         DALI_LOG_ERROR("Unknown error");
454       }
455     }
456     DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
457   }
458
459   if ( numConfigs != 1 )
460   {
461     DALI_LOG_ERROR("No configurations found.");
462     TEST_EGL_ERROR("eglChooseConfig");
463   }
464 }
465
466
467 void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
468 {
469   DALI_ASSERT_ALWAYS( ( mCurrentEglSurface == 0 ) && "EGL surface already exists" );
470
471   mColorDepth = depth;
472   mIsWindow = true;
473
474   // egl choose config
475   static_cast<void>(window);
476   EGLNativeWindowType dummyWindow = NULL;
477
478   mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, dummyWindow, NULL );
479
480
481   TEST_EGL_ERROR("eglCreateWindowSurface");
482
483   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
484 }
485
486
487 EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
488 {
489   DALI_ASSERT_ALWAYS( mCurrentEglSurface == 0 && "Cannot create more than one instance of surface pixmap" );
490
491   mCurrentEglNativePixmap = pixmap;
492   mColorDepth = depth;
493   mIsWindow = false;
494
495   // egl choose config
496   ChooseConfig(mIsWindow, mColorDepth);
497
498   mCurrentEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mCurrentEglNativePixmap, NULL );
499   TEST_EGL_ERROR("eglCreatePixmapSurface");
500
501   DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create pixmap surface failed" );
502
503   return mCurrentEglSurface;
504 }
505
506 bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window )
507 {
508   DALI_ASSERT_ALWAYS(!"Unimplemented");
509
510   bool contextLost = false;
511
512   //  the surface is bound to the context, so set the context to null
513   MakeContextNull();
514
515   // destroy the surface
516   DestroySurface();
517
518   // create the EGL surface
519   CreateSurfaceWindow( window, mColorDepth );
520
521   // set the context to be current with the new surface
522   MakeContextCurrent();
523
524   return contextLost;
525 }
526
527 bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface  )
528 {
529   bool contextLost = false;
530
531   //  the surface is bound to the context, so set the context to null
532   MakeContextNull();
533
534   // destroy the surface
535   DestroySurface();
536
537   // create the EGL surface
538   eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );
539
540   // set the context to be current with the new surface
541   MakeContextCurrent();
542
543   return contextLost;
544 }
545
546 EGLDisplay EglImplementation::GetDisplay() const
547 {
548   return mEglDisplay;
549 }
550
551 EGLDisplay EglImplementation::GetContext() const
552 {
553   return mEglContext;
554 }
555
556 } // namespace Adaptor
557
558 } // namespace Internal
559
560 } // namespace Dali
561