[Tizen] Support Ecore-Wayland2
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / tizen-wayland / ecore-wl2 / window-render-surface-ecore-wl2.cpp
1 /*
2  * Copyright (c) 2018 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 // CLASS HEADER
19 #include <dali/internal/window-system/tizen-wayland/ecore-wl2/window-render-surface-ecore-wl2.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/graphics/gles20/egl-implementation.h>
27 #include <dali/internal/adaptor/common/adaptor-impl.h>
28 #include <dali/integration-api/trigger-event-factory-interface.h>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34 namespace Adaptor
35 {
36
37 namespace
38 {
39
40 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
41
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE_ECORE_WL2");
44 #endif
45
46 } // unnamed namespace
47
48 WindowRenderSurfaceEcoreWl2::WindowRenderSurfaceEcoreWl2( Dali::PositionSize positionSize,
49                                                         Any surface,
50                                                         const std::string& name,
51                                                         bool isTransparent)
52 : mTitle( name ),
53   mPositionSize( positionSize ),
54   mWlWindow( NULL ),
55   mWlSurface( NULL ),
56   mEglWindow( NULL ),
57   mThreadSynchronization( NULL ),
58   mRenderNotification( NULL ),
59   mRotationTrigger( NULL ),
60   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
61   mRotationAngle( 0 ),
62   mScreenRotationAngle( 0 ),
63   mOwnSurface( false ),
64   mRotationSupported( false ),
65   mRotationFinished( true ),
66   mScreenRotationFinished( true ),
67   mResizeFinished( true )
68 {
69   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
70   Initialize( surface );
71 }
72
73 WindowRenderSurfaceEcoreWl2::~WindowRenderSurfaceEcoreWl2()
74 {
75   if( mEglWindow != NULL )
76   {
77     wl_egl_window_destroy(mEglWindow);
78     mEglWindow = NULL;
79   }
80
81   if( mOwnSurface )
82   {
83     ecore_wl2_window_free( mWlWindow );
84   }
85
86   if( mRotationTrigger )
87   {
88     delete mRotationTrigger;
89   }
90
91   if( mOwnSurface )
92   {
93     ecore_wl2_shutdown();
94   }
95 }
96
97 void WindowRenderSurfaceEcoreWl2::Initialize( Any surface )
98 {
99   // see if there is a surface in Any surface
100   unsigned int surfaceId = GetSurfaceId( surface );
101
102   // if the surface is empty, create a new one.
103   if( surfaceId == 0 )
104   {
105     // we own the surface about to created
106     ecore_wl2_init();
107     mOwnSurface = true;
108     CreateRenderable();
109   }
110   else
111   {
112     // XLib should already be initialized so no point in calling XInitThreads
113     UseExistingRenderable( surfaceId );
114   }
115 }
116
117 Ecore_Wl2_Window* WindowRenderSurfaceEcoreWl2::GetWlWindow()
118 {
119   return mWlWindow;
120 }
121
122 void WindowRenderSurfaceEcoreWl2::OutputTransformed()
123 {
124   int transform;
125
126   if( ecore_wl2_window_ignore_output_transform_get( mWlWindow ) )
127   {
128     transform = 0;
129   }
130   else
131   {
132     transform = ecore_wl2_output_transform_get( ecore_wl2_window_output_find( mWlWindow ) );
133   }
134
135   mScreenRotationAngle = transform * 90;
136   mScreenRotationFinished = false;
137
138   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
139 }
140
141 Any WindowRenderSurfaceEcoreWl2::GetWindow()
142 {
143   return mWlWindow;
144 }
145
146 void WindowRenderSurfaceEcoreWl2::Map()
147 {
148   ecore_wl2_window_show( mWlWindow );
149 }
150
151 void WindowRenderSurfaceEcoreWl2::SetRenderNotification( TriggerEventInterface* renderNotification )
152 {
153   mRenderNotification = renderNotification;
154 }
155
156 void WindowRenderSurfaceEcoreWl2::SetTransparency( bool transparent )
157 {
158   ecore_wl2_window_alpha_set( mWlWindow, transparent );
159 }
160
161 void WindowRenderSurfaceEcoreWl2::RequestRotation( int angle, int width, int height )
162 {
163   if( !mRotationSupported )
164   {
165     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::Rotate: Rotation is not supported!\n" );
166     return;
167   }
168
169   if( !mRotationTrigger )
170   {
171     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
172     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurfaceEcoreWl2::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
173   }
174
175   mPositionSize.width = width;
176   mPositionSize.height = height;
177
178   mRotationAngle = angle;
179   mRotationFinished = false;
180
181   ecore_wl2_window_rotation_set( mWlWindow, mRotationAngle );
182
183   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
184 }
185
186 PositionSize WindowRenderSurfaceEcoreWl2::GetPositionSize() const
187 {
188   return mPositionSize;
189 }
190
191 void WindowRenderSurfaceEcoreWl2::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
192 {
193   // calculate DPI
194   float xres, yres;
195
196   Ecore_Wl2_Output* output = ecore_wl2_window_output_find( mWlWindow );
197
198   // 1 inch = 25.4 millimeters
199   xres = ecore_wl2_output_dpi_get( output );
200   yres = ecore_wl2_output_dpi_get( output );
201
202   dpiHorizontal = int( xres + 0.5f );  // rounding
203   dpiVertical   = int( yres + 0.5f );
204 }
205
206 void WindowRenderSurfaceEcoreWl2::InitializeEgl( EglInterface& eglIf )
207 {
208   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
209
210   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
211
212   eglImpl.ChooseConfig(true, mColorDepth);
213 }
214
215 void WindowRenderSurfaceEcoreWl2::CreateEglSurface( EglInterface& eglIf )
216 {
217   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
218
219   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
220
221   // create the EGL window
222   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
223   {
224     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
225   }
226   else
227   {
228     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
229   }
230
231   EGLNativeWindowType windowType( mEglWindow );
232   eglImpl.CreateSurfaceWindow( windowType, mColorDepth );
233
234   // Check capability
235   wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( wl_egl_window_get_capabilities( mEglWindow ) );
236   if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
237   {
238     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::CreateEglSurface: capability = %d\n", capability );
239     mRotationSupported = true;
240   }
241
242   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::CreateEglSurface: w = %d h = %d angle = %d screen rotation = %d\n", mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
243 }
244
245 void WindowRenderSurfaceEcoreWl2::DestroyEglSurface( EglInterface& eglIf )
246 {
247   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
248
249   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
250   eglImpl.DestroySurface();
251
252   if( mEglWindow != NULL )
253   {
254     wl_egl_window_destroy(mEglWindow);
255     mEglWindow = NULL;
256   }
257 }
258
259 bool WindowRenderSurfaceEcoreWl2::ReplaceEGLSurface( EglInterface& egl )
260 {
261   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
262
263   if( mEglWindow != NULL )
264   {
265     wl_egl_window_destroy(mEglWindow);
266     mEglWindow = NULL;
267   }
268
269   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
270   {
271     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
272   }
273   else
274   {
275     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
276   }
277
278   // Set screen rotation
279   mScreenRotationFinished = false;
280
281   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
282   EGLNativeWindowType windowType( mEglWindow );
283   return eglImpl.ReplaceSurfaceWindow( windowType );
284 }
285
286 void WindowRenderSurfaceEcoreWl2::MoveResize( Dali::PositionSize positionSize )
287 {
288   bool needToMove = false;
289   bool needToResize = false;
290
291   // check moving
292   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
293       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
294   {
295     needToMove = true;
296   }
297
298   // check resizing
299   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
300       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
301   {
302     needToResize = true;
303   }
304
305   if( needToMove || needToResize )
306   {
307     ecore_wl2_window_geometry_set( mWlWindow, positionSize.x, positionSize.y, positionSize.width, positionSize.height );
308
309     if( needToResize )
310     {
311       mResizeFinished = false;
312     }
313   }
314
315   mPositionSize = positionSize;
316
317   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
318 }
319
320 void WindowRenderSurfaceEcoreWl2::SetViewMode( ViewMode viewMode )
321 {
322 }
323
324 void WindowRenderSurfaceEcoreWl2::StartRender()
325 {
326 }
327
328 bool WindowRenderSurfaceEcoreWl2::PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, bool resizingSurface )
329 {
330   if( resizingSurface )
331   {
332 #ifdef OVER_TIZEN_VERSION_4
333     // Window rotate or screen rotate
334     if( !mRotationFinished || !mScreenRotationFinished )
335     {
336       wl_egl_window_rotation rotation;
337       wl_output_transform bufferTransform;
338       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
339
340       switch( totalAngle )
341       {
342         case 0:
343         {
344           rotation = ROTATION_0;
345           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
346           break;
347         }
348         case 90:
349         {
350           rotation = ROTATION_270;
351           bufferTransform = WL_OUTPUT_TRANSFORM_90;
352           break;
353         }
354         case 180:
355         {
356           rotation = ROTATION_180;
357           bufferTransform = WL_OUTPUT_TRANSFORM_180;
358           break;
359         }
360         case 270:
361         {
362           rotation = ROTATION_90;
363           bufferTransform = WL_OUTPUT_TRANSFORM_270;
364           break;
365         }
366         default:
367         {
368           rotation = ROTATION_0;
369           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
370           break;
371         }
372       }
373
374       wl_egl_window_set_rotation( mEglWindow, rotation );
375
376       wl_egl_window_set_buffer_transform( mEglWindow, bufferTransform );
377
378       // Reset only screen rotation flag
379       mScreenRotationFinished = true;
380
381       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
382     }
383
384     // Only window rotate
385     if( !mRotationFinished )
386     {
387       wl_output_transform windowTransform;
388
389       switch( mRotationAngle )
390       {
391         case 0:
392         {
393           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
394           break;
395         }
396         case 90:
397         {
398           windowTransform = WL_OUTPUT_TRANSFORM_90;
399           break;
400         }
401         case 180:
402         {
403           windowTransform = WL_OUTPUT_TRANSFORM_180;
404           break;
405         }
406         case 270:
407         {
408           windowTransform = WL_OUTPUT_TRANSFORM_270;
409           break;
410         }
411         default:
412         {
413           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
414           break;
415         }
416       }
417
418       wl_egl_window_set_window_transform( mEglWindow, windowTransform );
419     }
420 #endif
421
422     // Resize case
423     if( !mResizeFinished )
424     {
425       wl_egl_window_resize( mEglWindow, mPositionSize.width, mPositionSize.height, mPositionSize.x, mPositionSize.y );
426       mResizeFinished = true;
427
428       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::PreRender: Set resize\n" );
429     }
430   }
431
432   return true;
433 }
434
435 void WindowRenderSurfaceEcoreWl2::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
436 {
437   if( resizingSurface )
438   {
439     if( !mRotationFinished )
440     {
441       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::PostRender: Trigger rotation event\n" );
442
443       mRotationTrigger->Trigger();
444
445       if( mThreadSynchronization )
446       {
447         // Wait until the event-thread complete the rotation event processing
448         mThreadSynchronization->PostRenderWaitForCompletion();
449       }
450     }
451   }
452
453   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
454   eglImpl.SwapBuffers();
455
456   if( mRenderNotification )
457   {
458     mRenderNotification->Trigger();
459   }
460 }
461
462 void WindowRenderSurfaceEcoreWl2::StopRender()
463 {
464 }
465
466 void WindowRenderSurfaceEcoreWl2::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
467 {
468   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::SetThreadSynchronization: called\n" );
469
470   mThreadSynchronization = &threadSynchronization;
471 }
472
473 void WindowRenderSurfaceEcoreWl2::ReleaseLock()
474 {
475   // Nothing to do.
476 }
477
478 RenderSurface::Type WindowRenderSurfaceEcoreWl2::GetSurfaceType()
479 {
480   return RenderSurface::WINDOW_RENDER_SURFACE;
481 }
482
483 void WindowRenderSurfaceEcoreWl2::CreateRenderable()
484 {
485   Ecore_Wl2_Display* display = ecore_wl2_display_connect( NULL );
486   if ( !display )
487   {
488     DALI_ASSERT_ALWAYS(0 && "Failed to get display");
489   }
490
491    // if width or height are zero, go full screen.
492   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
493   {
494     // Default window size == screen size
495     mPositionSize.x = 0;
496     mPositionSize.y = 0;
497
498     ecore_wl2_display_screen_size_get( display, &mPositionSize.width, &mPositionSize.height );
499   }
500
501   mWlWindow = ecore_wl2_window_new( display, NULL, mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
502
503   if ( mWlWindow == 0 )
504   {
505     DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
506   }
507
508   mWlSurface = ecore_wl2_window_surface_get( mWlWindow );
509
510   if( mColorDepth == COLOR_DEPTH_32 )
511   {
512     ecore_wl2_window_alpha_set( mWlWindow, true );
513   }
514   else
515   {
516     ecore_wl2_window_alpha_set( mWlWindow, false );
517   }
518
519   ecore_wl2_window_type_set( mWlWindow, ECORE_WL2_WINDOW_TYPE_TOPLEVEL );
520
521   // Get output transform
522   if( !ecore_wl2_window_ignore_output_transform_get( mWlWindow ) )
523   {
524     Ecore_Wl2_Output* output = ecore_wl2_window_output_find( mWlWindow );
525
526     int transform = ecore_wl2_output_transform_get( output );
527
528     mScreenRotationAngle = transform * 90;
529     mScreenRotationFinished = false;
530   }
531 }
532
533 void WindowRenderSurfaceEcoreWl2::UseExistingRenderable( unsigned int surfaceId )
534 {
535   mWlWindow = AnyCast< Ecore_Wl2_Window* >( surfaceId );
536 }
537
538 unsigned int WindowRenderSurfaceEcoreWl2::GetSurfaceId( Any surface ) const
539 {
540   unsigned int surfaceId = 0;
541
542   if( surface.Empty() == false )
543   {
544     // check we have a valid type
545     DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (Ecore_Wl2_Window *) ) )
546                         && "Surface type is invalid" );
547
548     surfaceId = AnyCast<unsigned int>( surface );
549   }
550   return surfaceId;
551 }
552
553 void WindowRenderSurfaceEcoreWl2::ProcessRotationRequest()
554 {
555   mRotationFinished = true;
556
557   ecore_wl2_window_rotation_change_done_send( mWlWindow, mRotationAngle, mPositionSize.width, mPositionSize.height );
558
559   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl2::ProcessRotationRequest: Rotation Done\n" );
560
561   if( mThreadSynchronization )
562   {
563     mThreadSynchronization->PostRenderComplete();
564   }
565 }
566
567 } // namespace Adaptor
568
569 } // namespace internal
570
571 } // namespace Dali