[4.0] Supports screen rotation.
[platform/core/uifw/dali-adaptor.git] / adaptors / ecore / wayland / window-render-surface-ecore-wl.cpp
1 /*
2  * Copyright (c) 2017 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 <window-render-surface.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 <wl-types.h>
27 #include <gl/egl-implementation.h>
28 #include <adaptors/common/adaptor-impl.h>
29 #include <integration-api/trigger-event-factory-interface.h>
30
31 namespace Dali
32 {
33
34 #if defined(DEBUG_ENABLED)
35 extern Debug::Filter* gRenderSurfaceLogFilter;
36 #endif
37
38 namespace ECore
39 {
40
41 namespace
42 {
43
44 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
45
46 } // unnamed namespace
47
48 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize,
49                                           Any surface,
50                                           const std::string& name,
51                                           bool isTransparent)
52 : EcoreWlRenderSurface( positionSize, surface, name, isTransparent ),
53   mWlWindow( NULL ),
54   mWlSurface( NULL ),
55   mEglWindow( NULL ),
56   mThreadSynchronization( NULL ),
57   mRotationTrigger( NULL ),
58   mRotationAngle( 0 ),
59   mScreenRotationAngle( 0 ),
60   mRotationSupported( false ),
61   mRotationFinished( true ),
62   mScreenRotationFinished( true ),
63   mResizeFinished( true )
64 {
65   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
66   Init( surface );
67 }
68
69 WindowRenderSurface::~WindowRenderSurface()
70 {
71   if( mEglWindow != NULL )
72   {
73     wl_egl_window_destroy(mEglWindow);
74     mEglWindow = NULL;
75   }
76
77   if( mOwnSurface )
78   {
79     ecore_wl_window_free( mWlWindow );
80   }
81
82   if( mRotationTrigger )
83   {
84     delete mRotationTrigger;
85   }
86
87 }
88
89 Ecore_Wl_Window* WindowRenderSurface::GetDrawable()
90 {
91   // already an e-core type
92   return mWlWindow;
93 }
94
95 Any WindowRenderSurface::GetSurface()
96 {
97   // already an e-core type
98   return Any( mWlWindow );
99 }
100
101 Ecore_Wl_Window* WindowRenderSurface::GetWlWindow()
102 {
103   return mWlWindow;
104 }
105
106 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
107 {
108   if( !mRotationSupported )
109   {
110     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
111     return;
112   }
113
114   if( !mRotationTrigger )
115   {
116     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
117     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
118   }
119
120   mPositionSize.width = width;
121   mPositionSize.height = height;
122
123   mRotationAngle = angle;
124   mRotationFinished = false;
125
126   ecore_wl_window_rotation_set( mWlWindow, mRotationAngle );
127
128   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
129 }
130
131 int WindowRenderSurface::OutputTransformed()
132 {
133   int transform;
134
135   if( !ecore_wl_window_ignore_output_transform_get( mWlWindow ) )
136   {
137     transform = ecore_wl_output_transform_get( ecore_wl_window_output_find( mWlWindow ) );
138     mScreenRotationAngle = transform * 90;
139     mScreenRotationFinished = false;
140     mResizeFinished = false;
141   }
142   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
143   return  (mRotationAngle + mScreenRotationAngle) % 360;
144 }
145
146 void WindowRenderSurface::SetTransparency( bool transparent )
147 {
148   ecore_wl_window_alpha_set( mWlWindow, transparent );
149 }
150
151 void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
152 {
153   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
154
155   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
156
157   eglImpl.ChooseConfig(true, mColorDepth);
158 }
159
160 void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
161 {
162   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
163
164   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
165
166   // create the EGL window
167   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
168   {
169     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
170   }
171   else
172   {
173     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
174   }
175
176   EGLNativeWindowType windowType( mEglWindow );
177   eglImpl.CreateSurfaceWindow( windowType, mColorDepth );
178
179   // Check capability
180   wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( wl_egl_window_get_capabilities( mEglWindow ) );
181   if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
182   {
183     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: capability = %d\n", capability );
184     mRotationSupported = true;
185   }
186
187   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: w = %d h = %d angle = %d screen rotation = %d\n", mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
188 }
189
190 void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
191 {
192   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
193
194   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
195   eglImpl.DestroySurface();
196
197   if( mEglWindow != NULL )
198   {
199     wl_egl_window_destroy(mEglWindow);
200     mEglWindow = NULL;
201   }
202 }
203
204 bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
205 {
206   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
207
208   if( mEglWindow != NULL )
209   {
210     wl_egl_window_destroy(mEglWindow);
211     mEglWindow = NULL;
212   }
213
214   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
215   {
216     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
217   }
218   else
219   {
220     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
221   }
222
223   // Set screen rotation
224   mScreenRotationFinished = false;
225
226   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
227   EGLNativeWindowType windowType( mEglWindow );
228   return eglImpl.ReplaceSurfaceWindow( windowType );
229 }
230
231 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
232 {
233   bool needToMove = false;
234   bool needToResize = false;
235
236   // check moving
237   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
238       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
239   {
240     needToMove = true;
241   }
242
243   // check resizing
244   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
245       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
246   {
247     needToResize = true;
248   }
249
250   if( needToMove )
251   {
252     ecore_wl_window_position_set( mWlWindow, positionSize.x, positionSize.y );
253   }
254   if( needToResize )
255   {
256     ecore_wl_window_update_size( mWlWindow, positionSize.width, positionSize.height );
257     mResizeFinished = false;
258   }
259
260   mPositionSize = positionSize;
261
262   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
263 }
264
265 void WindowRenderSurface::Map()
266 {
267   ecore_wl_window_show(mWlWindow);
268 }
269
270 void WindowRenderSurface::StartRender()
271 {
272 }
273
274 bool WindowRenderSurface::PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, bool resizingSurface )
275 {
276   if( resizingSurface )
277   {
278     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
279 #ifdef OVER_TIZEN_VERSION_4
280     // Window rotate or screen rotate
281     if( !mRotationFinished || !mScreenRotationFinished )
282     {
283       wl_egl_window_rotation rotation;
284       wl_output_transform bufferTransform;
285
286       switch( totalAngle )
287       {
288         case 0:
289         {
290           rotation = ROTATION_0;
291           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
292           break;
293         }
294         case 90:
295         {
296           rotation = ROTATION_270;
297           bufferTransform = WL_OUTPUT_TRANSFORM_90;
298           break;
299         }
300         case 180:
301         {
302           rotation = ROTATION_180;
303           bufferTransform = WL_OUTPUT_TRANSFORM_180;
304           break;
305         }
306         case 270:
307         {
308           rotation = ROTATION_90;
309           bufferTransform = WL_OUTPUT_TRANSFORM_270;
310           break;
311         }
312         default:
313         {
314           rotation = ROTATION_0;
315           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
316           break;
317         }
318       }
319
320       wl_egl_window_set_rotation( mEglWindow, rotation );
321
322       wl_egl_window_set_buffer_transform( mEglWindow, bufferTransform );
323
324       // Reset only screen rotation flag
325       mScreenRotationFinished = true;
326
327       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
328     }
329
330     // Only window rotate
331     if( !mRotationFinished )
332     {
333       wl_output_transform windowTransform;
334
335       switch( mRotationAngle )
336       {
337         case 0:
338         {
339           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
340           break;
341         }
342         case 90:
343         {
344           windowTransform = WL_OUTPUT_TRANSFORM_90;
345           break;
346         }
347         case 180:
348         {
349           windowTransform = WL_OUTPUT_TRANSFORM_180;
350           break;
351         }
352         case 270:
353         {
354           windowTransform = WL_OUTPUT_TRANSFORM_270;
355           break;
356         }
357         default:
358         {
359           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
360           break;
361         }
362       }
363
364       wl_egl_window_set_window_transform( mEglWindow, windowTransform );
365     }
366 #endif
367
368     // Resize case
369     if( !mResizeFinished )
370     {
371       if( totalAngle == 0 || totalAngle == 180 )
372       {
373         wl_egl_window_resize( mEglWindow, mPositionSize.width, mPositionSize.height, mPositionSize.x, mPositionSize.y );
374       }
375       else
376       {
377         wl_egl_window_resize( mEglWindow, mPositionSize.height, mPositionSize.width, mPositionSize.x, mPositionSize.y );
378       }
379       mResizeFinished = true;
380
381       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
382     }
383   }
384
385   return true;
386 }
387
388 void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
389 {
390   if( resizingSurface )
391   {
392     if( !mRotationFinished )
393     {
394       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
395
396       mRotationTrigger->Trigger();
397
398       if( mThreadSynchronization )
399       {
400         // Wait until the event-thread complete the rotation event processing
401         mThreadSynchronization->PostRenderWaitForCompletion();
402       }
403     }
404   }
405
406   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
407   eglImpl.SwapBuffers();
408
409   if( mRenderNotification )
410   {
411     mRenderNotification->Trigger();
412   }
413 }
414
415 void WindowRenderSurface::StopRender()
416 {
417 }
418
419 void WindowRenderSurface::SetViewMode( ViewMode viewMode )
420 {
421   //FIXME
422 }
423
424 void WindowRenderSurface::CreateWlRenderable()
425 {
426    // if width or height are zero, go full screen.
427   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
428   {
429     // Default window size == screen size
430     mPositionSize.x = 0;
431     mPositionSize.y = 0;
432
433     ecore_wl_screen_size_get( &mPositionSize.width, &mPositionSize.height );
434   }
435
436   mWlWindow = ecore_wl_window_new( 0, mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
437
438   if ( mWlWindow == 0 )
439   {
440     DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
441   }
442
443   mWlSurface = ecore_wl_window_surface_create( mWlWindow );
444
445   if( mColorDepth == COLOR_DEPTH_32 )
446   {
447     ecore_wl_window_alpha_set( mWlWindow, true );
448   }
449   else
450   {
451     ecore_wl_window_alpha_set( mWlWindow, false );
452   }
453
454   // Get output transform
455   if( !ecore_wl_window_ignore_output_transform_get( mWlWindow ) )
456   {
457     Ecore_Wl_Output* output = ecore_wl_window_output_find( mWlWindow );
458
459     int transform = ecore_wl_output_transform_get( output );
460
461     mScreenRotationAngle = transform * 90;
462     mScreenRotationFinished = false;
463   }
464 }
465
466 void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
467 {
468   mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
469 }
470
471 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
472 {
473   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
474
475   mThreadSynchronization = &threadSynchronization;
476 }
477
478 void WindowRenderSurface::ReleaseLock()
479 {
480   // Nothing to do.
481 }
482
483 void WindowRenderSurface::ProcessRotationRequest()
484 {
485   mRotationFinished = true;
486
487   ecore_wl_window_rotation_change_done_send( mWlWindow );
488
489   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
490
491   if( mThreadSynchronization )
492   {
493     mThreadSynchronization->PostRenderComplete();
494   }
495 }
496
497 } // namespace ECore
498
499 } // namespace Dali