[Tizen] Support Ecore-Wayland2
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / tizen-wayland / ecore-wl / window-render-surface-ecore-wl.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-wl/window-render-surface-ecore-wl.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_WL");
44 #endif
45
46 } // unnamed namespace
47
48 WindowRenderSurfaceEcoreWl::WindowRenderSurfaceEcoreWl( 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 WindowRenderSurfaceEcoreWl::~WindowRenderSurfaceEcoreWl()
74 {
75   if( mEglWindow != NULL )
76   {
77     wl_egl_window_destroy(mEglWindow);
78     mEglWindow = NULL;
79   }
80
81   if( mOwnSurface )
82   {
83     ecore_wl_window_free( mWlWindow );
84   }
85
86   if( mRotationTrigger )
87   {
88     delete mRotationTrigger;
89   }
90
91   if( mOwnSurface )
92   {
93     ecore_wl_shutdown();
94   }
95 }
96
97 void WindowRenderSurfaceEcoreWl::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_wl_init( NULL );
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_Wl_Window* WindowRenderSurfaceEcoreWl::GetWlWindow()
118 {
119   return mWlWindow;
120 }
121
122 void WindowRenderSurfaceEcoreWl::OutputTransformed()
123 {
124   int transform;
125
126   if( ecore_wl_window_ignore_output_transform_get( mWlWindow ) )
127   {
128     transform = 0;
129   }
130   else
131   {
132     transform = ecore_wl_output_transform_get( ecore_wl_window_output_find( mWlWindow ) );
133   }
134
135   mScreenRotationAngle = transform * 90;
136   mScreenRotationFinished = false;
137
138   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
139 }
140
141 Any WindowRenderSurfaceEcoreWl::GetWindow()
142 {
143   return mWlWindow;
144 }
145
146 void WindowRenderSurfaceEcoreWl::Map()
147 {
148   ecore_wl_window_show( mWlWindow );
149 }
150
151 void WindowRenderSurfaceEcoreWl::SetRenderNotification( TriggerEventInterface* renderNotification )
152 {
153   mRenderNotification = renderNotification;
154 }
155
156 void WindowRenderSurfaceEcoreWl::SetTransparency( bool transparent )
157 {
158   ecore_wl_window_alpha_set( mWlWindow, transparent );
159 }
160
161 void WindowRenderSurfaceEcoreWl::RequestRotation( int angle, int width, int height )
162 {
163   if( !mRotationSupported )
164   {
165     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::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, &WindowRenderSurfaceEcoreWl::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_wl_window_rotation_set( mWlWindow, mRotationAngle );
182
183   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
184 }
185
186 PositionSize WindowRenderSurfaceEcoreWl::GetPositionSize() const
187 {
188   return mPositionSize;
189 }
190
191 void WindowRenderSurfaceEcoreWl::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
192 {
193   // calculate DPI
194   float xres, yres;
195
196   // 1 inch = 25.4 millimeters
197   xres = ecore_wl_dpi_get();
198   yres = ecore_wl_dpi_get();
199
200   dpiHorizontal = int( xres + 0.5f );  // rounding
201   dpiVertical   = int( yres + 0.5f );
202 }
203
204 void WindowRenderSurfaceEcoreWl::InitializeEgl( EglInterface& eglIf )
205 {
206   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
207
208   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
209
210   eglImpl.ChooseConfig(true, mColorDepth);
211 }
212
213 void WindowRenderSurfaceEcoreWl::CreateEglSurface( EglInterface& eglIf )
214 {
215   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
216
217   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
218
219   // create the EGL window
220   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
221   {
222     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
223   }
224   else
225   {
226     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
227   }
228
229   EGLNativeWindowType windowType( mEglWindow );
230   eglImpl.CreateSurfaceWindow( windowType, mColorDepth );
231
232   // Check capability
233   wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( wl_egl_window_get_capabilities( mEglWindow ) );
234   if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
235   {
236     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::CreateEglSurface: capability = %d\n", capability );
237     mRotationSupported = true;
238   }
239
240   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::CreateEglSurface: w = %d h = %d angle = %d screen rotation = %d\n", mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
241 }
242
243 void WindowRenderSurfaceEcoreWl::DestroyEglSurface( EglInterface& eglIf )
244 {
245   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
246
247   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
248   eglImpl.DestroySurface();
249
250   if( mEglWindow != NULL )
251   {
252     wl_egl_window_destroy(mEglWindow);
253     mEglWindow = NULL;
254   }
255 }
256
257 bool WindowRenderSurfaceEcoreWl::ReplaceEGLSurface( EglInterface& egl )
258 {
259   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
260
261   if( mEglWindow != NULL )
262   {
263     wl_egl_window_destroy(mEglWindow);
264     mEglWindow = NULL;
265   }
266
267   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
268   {
269     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
270   }
271   else
272   {
273     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
274   }
275
276   // Set screen rotation
277   mScreenRotationFinished = false;
278
279   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
280   EGLNativeWindowType windowType( mEglWindow );
281   return eglImpl.ReplaceSurfaceWindow( windowType );
282 }
283
284 void WindowRenderSurfaceEcoreWl::MoveResize( Dali::PositionSize positionSize )
285 {
286   bool needToMove = false;
287   bool needToResize = false;
288
289   // check moving
290   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
291       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
292   {
293     needToMove = true;
294   }
295
296   // check resizing
297   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
298       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
299   {
300     needToResize = true;
301   }
302
303   if( needToMove )
304   {
305     ecore_wl_window_position_set( mWlWindow, positionSize.x, positionSize.y );
306   }
307   if( needToResize )
308   {
309     ecore_wl_window_update_size( mWlWindow, positionSize.width, positionSize.height );
310     mResizeFinished = false;
311   }
312
313   mPositionSize = positionSize;
314
315   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
316 }
317
318 void WindowRenderSurfaceEcoreWl::SetViewMode( ViewMode viewMode )
319 {
320 }
321
322 void WindowRenderSurfaceEcoreWl::StartRender()
323 {
324 }
325
326 bool WindowRenderSurfaceEcoreWl::PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, bool resizingSurface )
327 {
328   if( resizingSurface )
329   {
330 #ifdef OVER_TIZEN_VERSION_4
331     // Window rotate or screen rotate
332     if( !mRotationFinished || !mScreenRotationFinished )
333     {
334       wl_egl_window_rotation rotation;
335       wl_output_transform bufferTransform;
336       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
337
338       switch( totalAngle )
339       {
340         case 0:
341         {
342           rotation = ROTATION_0;
343           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
344           break;
345         }
346         case 90:
347         {
348           rotation = ROTATION_270;
349           bufferTransform = WL_OUTPUT_TRANSFORM_90;
350           break;
351         }
352         case 180:
353         {
354           rotation = ROTATION_180;
355           bufferTransform = WL_OUTPUT_TRANSFORM_180;
356           break;
357         }
358         case 270:
359         {
360           rotation = ROTATION_90;
361           bufferTransform = WL_OUTPUT_TRANSFORM_270;
362           break;
363         }
364         default:
365         {
366           rotation = ROTATION_0;
367           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
368           break;
369         }
370       }
371
372       wl_egl_window_set_rotation( mEglWindow, rotation );
373
374       wl_egl_window_set_buffer_transform( mEglWindow, bufferTransform );
375
376       // Reset only screen rotation flag
377       mScreenRotationFinished = true;
378
379       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
380     }
381
382     // Only window rotate
383     if( !mRotationFinished )
384     {
385       wl_output_transform windowTransform;
386
387       switch( mRotationAngle )
388       {
389         case 0:
390         {
391           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
392           break;
393         }
394         case 90:
395         {
396           windowTransform = WL_OUTPUT_TRANSFORM_90;
397           break;
398         }
399         case 180:
400         {
401           windowTransform = WL_OUTPUT_TRANSFORM_180;
402           break;
403         }
404         case 270:
405         {
406           windowTransform = WL_OUTPUT_TRANSFORM_270;
407           break;
408         }
409         default:
410         {
411           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
412           break;
413         }
414       }
415
416       wl_egl_window_set_window_transform( mEglWindow, windowTransform );
417     }
418 #endif
419
420     // Resize case
421     if( !mResizeFinished )
422     {
423       wl_egl_window_resize( mEglWindow, mPositionSize.width, mPositionSize.height, mPositionSize.x, mPositionSize.y );
424       mResizeFinished = true;
425
426       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::PreRender: Set resize\n" );
427     }
428   }
429
430   return true;
431 }
432
433 void WindowRenderSurfaceEcoreWl::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
434 {
435   if( resizingSurface )
436   {
437     if( !mRotationFinished )
438     {
439       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::PostRender: Trigger rotation event\n" );
440
441       mRotationTrigger->Trigger();
442
443       if( mThreadSynchronization )
444       {
445         // Wait until the event-thread complete the rotation event processing
446         mThreadSynchronization->PostRenderWaitForCompletion();
447       }
448     }
449   }
450
451   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
452   eglImpl.SwapBuffers();
453
454   if( mRenderNotification )
455   {
456     mRenderNotification->Trigger();
457   }
458 }
459
460 void WindowRenderSurfaceEcoreWl::StopRender()
461 {
462 }
463
464 void WindowRenderSurfaceEcoreWl::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
465 {
466   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::SetThreadSynchronization: called\n" );
467
468   mThreadSynchronization = &threadSynchronization;
469 }
470
471 void WindowRenderSurfaceEcoreWl::ReleaseLock()
472 {
473   // Nothing to do.
474 }
475
476 RenderSurface::Type WindowRenderSurfaceEcoreWl::GetSurfaceType()
477 {
478   return RenderSurface::WINDOW_RENDER_SURFACE;
479 }
480
481 void WindowRenderSurfaceEcoreWl::CreateRenderable()
482 {
483    // if width or height are zero, go full screen.
484   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
485   {
486     // Default window size == screen size
487     mPositionSize.x = 0;
488     mPositionSize.y = 0;
489
490     ecore_wl_screen_size_get( &mPositionSize.width, &mPositionSize.height );
491   }
492
493   mWlWindow = ecore_wl_window_new( 0, mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
494
495   if ( mWlWindow == 0 )
496   {
497     DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
498   }
499
500   mWlSurface = ecore_wl_window_surface_create( mWlWindow );
501
502   if( mColorDepth == COLOR_DEPTH_32 )
503   {
504     ecore_wl_window_alpha_set( mWlWindow, true );
505   }
506   else
507   {
508     ecore_wl_window_alpha_set( mWlWindow, false );
509   }
510
511   // Get output transform
512   if( !ecore_wl_window_ignore_output_transform_get( mWlWindow ) )
513   {
514     Ecore_Wl_Output* output = ecore_wl_window_output_find( mWlWindow );
515
516     int transform = ecore_wl_output_transform_get( output );
517
518     mScreenRotationAngle = transform * 90;
519     mScreenRotationFinished = false;
520   }
521 }
522
523 void WindowRenderSurfaceEcoreWl::UseExistingRenderable( unsigned int surfaceId )
524 {
525   mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
526 }
527
528 unsigned int WindowRenderSurfaceEcoreWl::GetSurfaceId( Any surface ) const
529 {
530   unsigned int surfaceId = 0;
531
532   if( surface.Empty() == false )
533   {
534     // check we have a valid type
535     DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (Ecore_Wl_Window *) ) )
536                         && "Surface type is invalid" );
537
538     surfaceId = AnyCast<unsigned int>( surface );
539   }
540   return surfaceId;
541 }
542
543 void WindowRenderSurfaceEcoreWl::ProcessRotationRequest()
544 {
545   mRotationFinished = true;
546
547   ecore_wl_window_rotation_change_done_send( mWlWindow );
548
549   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurfaceEcoreWl::ProcessRotationRequest: Rotation Done\n" );
550
551   if( mThreadSynchronization )
552   {
553     mThreadSynchronization->PostRenderComplete();
554   }
555 }
556
557 } // namespace Adaptor
558
559 } // namespace internal
560
561 } // namespace Dali